AskaEth
|
394faad611
|
docs(termux): MC 1.20.4 真机跑通结论与剩余项
- README:MC 标 ✅(glibc JRE + arm64 natives + softpipe);后续收敛为
zink/DRI3、剪贴板/IME、narrator/音频
- 构建文档 §4.2 补真机启动命令、窗口尺寸与日志位置、非致命项
|
2026-11-07 09:33:23 +08:00 |
|
AskaEth
|
23c2abebc2
|
feat(termux): launch 侧同样改写 arm64 natives;真机跑通 MC 1.20.4
- Library::linux_arm64_native_name 收敛改写规则,install 与 launch 共用
- presenter/CLI 的 classpath 组装:1.19+ 的独立 natives 条目按 arm64 坐标
找文件并进 classpath;≤1.18 的 natives 表条目仍归 natives::collect
- 真机验证:ull install 1.20.4(740MB)→ glibc Temurin 21 + arm64 natives +
softpipe GL,MC 主菜单在 termux-x11 中渲染(窗口 854x480)
- 已知非致命:narrator flite 缺失、LWJGL JNI 版本告警、oshi cpuVendor NPE
|
2026-11-07 09:33:23 +08:00 |
|
AskaEth
|
0e7ae44923
|
fix(termux): 现代清单的 LWJGL natives 条目也改写为 arm64
1.20.x 把 natives 作为独立库条目(org.lwjgl:lwjgl:3.3.2:natives-linux),
不走 natives 表。Linux/aarch64 上按坐标改写成 natives-linux-arm64,
URL 兜底到阿里云 Maven(Mojang 对 arm64 一律 404)。
真机 1.20.4 的 dry-run:7 个 natives 全部变成 arm64;x86_64 不变。
|
2026-11-07 09:33:22 +08:00 |
|
AskaEth
|
7eed6c6261
|
feat(termux): MC 启动接线——Linux arm64 natives + softpipe 子进程环境
- Library::native_classifier:Linux/aarch64 上把 LWJGL3 的 natives-linux
改写成 natives-linux-arm64(Mojang 清单只有 x86_64)
- install::libraries:arm64 分类器在清单里没有下载信息时,按 Maven 相对路径
兜底到阿里云镜像(实测 Mojang libraries 404、Aliyun 200);
单测覆盖 arm64 兜底与 x86_64 不变
- launch::defaults:Termux glibc 构建启动 MC 时默认带
MESA_LOADER_DRIVER_OVERRIDE=swrast / LIBGL_ALWAYS_SOFTWARE=1(用户可覆盖)
- 文档:JRE patchelf 一次性步骤与接线现状;README 同步
- 验证:patched Temurin java 直接执行;LWJGL arm64+GLFW 探针 gl-ok
|
2026-11-07 09:33:22 +08:00 |
|
AskaEth
|
02ed09ae49
|
docs(termux): 补 MC 运行时结论(glibc JRE + LWJGL arm64 + softpipe GL)
- §4.2:Temurin 21 JRE 在 glibc 下跑通;AWT/X11 正常;
LWJGL 3.3.3 arm64 + GLFW + GLX/softpipe 端到端探针通过(GL 3.3)
- zink 仍卡 DRI3;softpipe 可用(软件 GL)
- README 同步:MC 标 🟡(栈已验证,启动器接线待做),后续改为接线 + DRI3
|
2026-11-07 09:33:22 +08:00 |
|
AskaEth
|
173a18b842
|
feat(termux): glibc 构建自动启用自编 Mesa 26 turnip ICD(GPU 打通)
- app/boot/termux_gpu:glibc 构建 + Termux 且随附 ICD 存在时,在探测前设
VK_ICD_FILENAMES/VK_DRIVER_FILES;用户显式设置不覆盖
- 文档:Mesa 26.2.6 + KGSL 的完整构建/安装/验证步骤(含 shebang、
--wrap-mode=nofallback、C++/链接参数三处坑)
- 实测:wgpu 选中 Adreno 840(turnip Mesa 26.2.6),截图首帧 61 ms
- README.termux:GPU 标 ✅,MC 标 🟡(glibc JRE+AWT 已验证,GLX 待 GL 构建)
|
2026-11-07 09:33:21 +08:00 |
|
AskaEth
|
bbb316ca08
|
docs(termux): GPU 结论落地——glibc 侧被驱动版本挡住
实测结论:
- glibc Vulkan loader + 自写 ICD 能加载
- Termux glibc Mesa 24.2.6 不认识 Adreno 840(chip 0x44050A31 unsupported)
- Arch vulkan-freedreno 26.2.6 能加载但 Linux/DRM 构建找不到设备(缺 KGSL,
/dev/dri 对 untrusted_app 被 SELinux 拒绝)
- GPU 变体会打印具名错误并自动降级 tiny-skia
README.termux 同步:GPU 标 ⛔、MC 走 glibc JVM 的结论与后续路线
|
2026-11-07 09:33:21 +08:00 |
|
AskaEth
|
c434dbe335
|
feat(termux): 横屏自适应窗口、安装后清理 apt 工作区、补分支 README
- app/boot/termux_window:Termux 上默认窗口按 X 屏幕等比自适应
(横屏铺满、竖屏不溢出,最大 2×;日志 source=termux-screen),
ULL_WINDOW_SIZE 覆盖与 1180×760 验收基准不变;5 条单测
- termux::install 成功后清理 $PREFIX/tmp/ull-java-termux(一次安装约 100 MB)
- 构建文档补 clippy/rustfmt 组件、cargo-clippy 目标被带成 android 的坑、
门禁命令、横屏行为与 openjdk-17 实测
- 新增 README.termux.md(分支定位/已验证矩阵/快速开始/边界/路线图),
两份主 README 的 Termux 条目链过去
|
2026-11-07 09:33:21 +08:00 |
|
AskaEth
|
7b971dc75d
|
fix(java): Termux 幂等安装报「未走网络」,vendors 在 Termux 上展示 termux 行
- termux::install 返回 (home, reused),复用时 downloaded=None,
CLI 不再显示「0 字节 / 0 个文件」
- java vendors 在 Termux 上把 termux 插到顺序最前(仅展示,默认回退序不变)
|
2026-11-07 09:33:20 +08:00 |
|
AskaEth
|
48d1ee6616
|
feat(java): Termux 上自动安装系统 openjdk(内置镜像 + 隔离 apt 状态)
- 新增 game::java::termux:内置 SAU/TUNA/USTC/官方四个 termux-main 镜像,
按顺序 apt-get update+install;lists/cache 隔离在 $PREFIX/tmp/ull-java-termux,
不改用户 apt 配置;装完从 $PREFIX/lib/jvm 定位,幂等(已装则不走网络)
- JdkVendor 增加 termux(17/21/25),--vendor termux 只走系统包;
Termux 上缺省安装先试系统包,失败再走归档链并带出每一跳原因
- standard_roots 已能扫 $PREFIX/lib/jvm(上一条提交),装完即被 java list 发现
- CLI/presenter 的 vendor 展示与帮助文案同步;设置白名单与契约测试同步
- 文档补 Termux 上的 Java 行为
|
2026-11-07 09:33:19 +08:00 |
|
AskaEth
|
1e0fc44fed
|
docs(packaging): 记录 Termux glibc 构建与 termux-x11 运行配方
新增 packaging/docs/termux-glibc-build.md:glibc 工具链(Rust gnu 组件 +
patchelf + clang/lld + Debian libgcc crt)、构建环境(LD_PRELOAD/CA/USTC 镜像)、
termux-x11 运行与截图取证、GPU 现状与已知边界。
支持矩阵四处同步:Termux 行从「GUI 未验证」改为「源码自建、CPU 渲染单机验证过」,
仍标注实验级、不在发布矩阵内。
|
2026-11-07 09:33:19 +08:00 |
|
AskaEth
|
4582a025db
|
fix(fonts): Termux 上注册 Android 系统 CJK 字体,消除中文方框
glibc 构建跑在 Termux 里时 target_os 仍是 linux,fontdb 只扫 Linux 常规
字体目录,/system/fonts 不在其中,中文实例名与界面文案全渲染成方框。
在字体求值入口按运行时识别 Termux,把 NotoSansCJK 等候选注册进
cosmic-text 的字体库(OnceLock 只加载一次,找不到就静默放过)。
app-iced 直接依赖 unlucky-core 复用平台识别,不再本地复制环境判断。
|
2026-11-07 09:33:18 +08:00 |
|
AskaEth
|
e090c67297
|
feat(platform): 识别 Termux 宿主并把 $PREFIX/lib/jvm 纳入 JDK 扫描
- 新增 platform::termux:用 TERMUX_VERSION / 默认 PREFIX 识别 Termux,
推导 $PREFIX 与 $PREFIX/lib/jvm,不把路径写死进调用方
- java::discover 的 standard_roots 在 Unix 分支追加 Termux 的 JVM 根,
环境可注入(standard_roots_in),补上「Termux 装了 openjdk 但没设
JAVA_HOME/PATH 就发现不了」的盲点
- 单测覆盖识别、负例与扫描结果
|
2026-11-07 09:33:18 +08:00 |
|
AskaEth
|
ac2e163eb8
|
Merge branch 'feat/m156guard-fix-bash-e-silent-kill-in-guar'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-07 09:20:21 +08:00 |
|
AskaEth
|
aa42496561
|
fix(ci): M156 修 guards.yml 三处 bash -e 静默自杀(presenter-no-ui 从未绿过)
M155 钉死:guards.yml 的 `hits=$(… | grep -iE …)` 在 grep 零命中(exit 1)时被
runner 默认的 `bash -e {0}` 拖红整步,且脚本里 `set -uo pipefail` 关不掉 -e,
所以一条 `::error::` 都打不出来 —— presenter-no-ui 自 M89 引入起从未绿过一次。
- presenter 依赖树 step:`hits=` 补 `|| true`(零命中回到绿路,真命中仍红)
- core 依赖树 step:裸 `tree=$(cargo tree …)` 改 `if ! tree=$(…)` 守卫,
与 presenter / design 两处对称,cargo tree 失败时打注解而不是静默退出
- unsafe-scope:`actual=$(git grep …)` 末尾补 `|| true`,零匹配不再中止整步
- 文件头加一条警示:「本文件所有 run: 都在 bash -e 下,裸管道/裸赋值会被静默杀死」
验证(M155 方法:step 脚本从 yml 原样切出、`bash -e` 执行):
presenter 零命中 改前 exit1/0 注解 → 改后 exit0 打 OK;真命中仍 exit1/2 注解;
core cargo tree 失败 改前 exit101/0 注解 → 改后 exit1/1 注解;unsafe 零匹配
改前 exit1/0 注解 → 改后 exit1/2 注解;两处正常路径均仍绿。pyyaml 可解析,398 行。
|
2026-11-07 09:15:10 +08:00 |
|
AskaEth
|
4bb1591aca
|
Merge branch 'feat/m152-packlast-finish-modpack-import-expo'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-07 08:34:11 +08:00 |
|
AskaEth
|
be280c16a3
|
fix(core): ZIP64 第二道闸不再重复累计预检总量(复审 P2-1)
复审在 tip 54c2d75 上实证的缺陷:`container()` 把 `preflight()` 返回的**全量**声明尺寸
当成写循环累加基数,循环里又对每个文件 `+= bytes.len()`,于是真实总量只要过半阈值
(~2.15 GiB)就被误拒,而且拒在内容读出来之后——"闸在内容进内存之前"的性质同时失效。
两处修:
1. 记账拆成独立类型 `Written`,**从清单 JSON 长度起算**,与预检返回值无关;预检的返回值
现在只给测试与诊断看(`let _ =`,文档写明不许当基数)。
2. 内容改成 1 MiB 缓冲流式写进 zip(`COPY_CHUNK`),不再 `std::fs::read` 整份摊在内存里。
第二道闸看的是"已写字节数",与内存占用解耦;顺带把"拿预检 total 当基数"这类写法
在内存侧也变成无害的小错而不是几个 GiB 的读。
测试(按塔台资源令,默认套件不再真写 2.5 GB):
- `write.rs` 新增 `the_container_does_not_double_count_the_preflight_total`:把阈值注入成
几十字节(`container`/`preflight`/`Written` 都收 `limit`,生产路径恒为
`zip::ZIP64_BYTES_THR`),构造"正确实现 70 < 90 通过 / 重复累计 110 ≥ 90 被拒"的窗口,
**0.01 秒**钉住 P2-1;实测把 bug 写回去即红。
- `write.rs` 新增 `the_second_gate_counts_from_the_manifest_length_not_the_preflight_total`:
直接对 `Written` 断言 2.5 GB 不拒、撞阈值必拒。
- `zip64.rs` 的 2.5 GB 稀疏文件端到端用例保留但 `#[ignore]`(真跑要 ~70 秒 deflate 与一大片
内存/页面文件,C 盘页面文件已被上一轮撑到 34.8G),实测过一次成功:条目声明尺寸原样
2 500 000 000、产物只有几 MB。跑法写在该用例的文档里。
门禁:fmt 0 / clippy -p unlucky-core --all-targets 0 / cargo test -p unlucky-core 1033 passed
0 failed(lib 480 passed + 1 ignored)。
|
2026-11-07 08:22:47 +08:00 |
|
AskaEth
|
d728ed836f
|
feat(core): M152 整合包收尾——同路径遮蔽逐文件上报 + ZIP64 拒写预检
导入侧把「同名文件冲突」从整包一个策略推进到逐文件事实:同一实例路径被本包多份声明
命中时(跨侧 overrides/client-overrides,或同侧重复),按叠层顺序(Both → Client)定
胜者,其余标 PlanOverride::shadowed(winner / winner_dir / same_bytes),逐条留
pack.import.note.override_shadowed 注记;phase 只遍历未被遮蔽的条目,不再白读字节,
报告里也不再出现"两条 Installed、前一条的哈希其实没落地"。
不新增 FileAction/ConflictReason 变体:这三个枚举被 crates/presenter 的 convert.rs
穷尽 match,而那个 crate 不在本 purpose 的作用域内,所以走既有的 ImportIssue 通道
(与 server-overrides/ 被跳过同一条)。
导出侧那条 ZIP64 闸原来够不着:先 std::fs::read 整个覆盖文件进内存再累加判断,真要
导出 4 GiB 文件的实例,内存先炸、用户永远看不到那句 pack_limits。改成写前按
metadata().len() 做声明尺寸预检,超阈值在任何字节进内存之前就报;写循环里的增量检查
留作第二道。写 zip 的实现搬到 format/write.rs 以守 400 行。
测试:pack/tests/zip64.rs(稀疏文件真跑到 ZIP64 分支,含累计口径与对照)、
tests/import_layering.rs(同路径不同哈希 / 同哈希不同路径 / 叠层顺序 / 基线记胜者)、
unknown_fields.rs 补第 4 条假边(mrpack files[].extra + 未知哈希算法)。
五条变异各自变红(遮蔽 no-op 6 红、按哈希判重 6 红、翻转叠层 2 红、错误码改 io 3 红、
预检不累计则预检单测红且端到端用例从 0.01s 变成 95s/约 4.5 GiB 内存)。
|
2026-11-07 08:22:47 +08:00 |
|
AskaEth
|
37de00b07e
|
Merge branch 'feat/m154-verb022-bump-workspace-version-to-0'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-07 08:16:39 +08:00 |
|
AskaEth
|
06fe12d811
|
chore(release): M154 版本升到 0.2.2(第一个稳定通道版本,D51)
- 根 Cargo.toml `[workspace.package] version` 0.2.1 → 0.2.2;`crates/{agent,app-iced,cli,palette-extract,
presenter}` 里 9 处 intra-workspace path 依赖的 version 约束一并对齐(M137 既定做法)。`crates/app` 是
workspace `exclude` 的 Slint 退役树,manifest 不参与解析,原样保留。
- Cargo.lock 由 cargo 再生成:只有 8 个 `unlucky-*` 成员条目从 0.2.1 变 0.2.2,第三方依赖(含版本号恰好
也是 0.2.1 的 hexf-parse / windows-link / windows-threading / xkeysym / yazi)一字未动。这一步不是可选:
CI 与发布流水线全走 `--locked`(ci.yml:236,274 / release-build.yml:135,142 / make_artifacts.py:50),
lock 不跟就是「tag 一打就红」。
- packaging 文档里的**示例 tag** 跟到 v0.2.2:docs/artifacts-and-version.md 两处(命名规则示例 + 「tag 说
X、产物里写 Y」的事故示例)、docs/build-and-ci.md 三处(`--version v…`、两次 `gh workflow run --ref v…`)、
docs/profiles-and-measurements.md 的「同一槽位现在叫 `unlucky-launcher_0.2.2_windows_x64.exe`」、
make_manifest.py 四处(Usage 示例 / `normalize_version` docstring / `--version` 的 argparse help)。
- **历史注记一律不动**:docs/runtime-deps.md 的「v0.2.1 首次真跑即红在工具链体检」(M140 事故记录)、
`.github/workflows/release.yml:71` 同一事故的另一处记录、`crates/core` 更新模块测试里的样本版本串
(`checker_cases.rs` / `version_cases.rs`,是解析器测试夹具,不是发布事实)、`microsoft.rs:224` 的
`21.0.13.0.2.1` 负例。
- README.md / README.zh-CN.md、packaging/release-notes.md 核实后**无需改动**:三份文件里没有任何写死的
版本号——下载表是 `<version>` / `<版本>` 占位符(M153 刚统一的口径,含非发布档位标「暂未发布」的行,
原样保留未回退),release-notes 正文是 `{{VERSION}}` / `{{SUMS}}` 模板占位符。
验证:`cargo check -p unlucky-cli --all-targets --locked` 过(编译日志里 unlucky-core/agent/cli 均报 v0.2.2)、
`cargo test -p unlucky-cli --lib --locked` 42 passed 0 failed、`cargo metadata --locked --offline` 过(全
workspace manifest + lock 一致)、`python3 packaging/make_manifest.py --self-test` ok、
`ull --version` 实跑输出 `ull 0.2.2(unlucky-cli)`。
|
2026-11-07 08:13:29 +08:00 |
|
AskaEth
|
c38fbe4068
|
Merge branch 'feat/m150-ghrsrc-implement-githubreleasesourc'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-07 08:06:31 +08:00 |
|
AskaEth
|
f001b93942
|
feat(core): M150 新增 GitHub Releases 更新源(D50)
D50 定案 GitHub Releases 为唯一更新源,清单地址固定为
`releases/latest/download/manifest.json`。此前 update 模块只有对拍用的
DirSource,这次把真实源补上。
- `update::github::GitHubReleaseSource` 实现 `UpdateSource`:清单从
`<base>/<owner>/<repo>/releases/latest/download/manifest.json` 取,
产物按 D49 命名规则(文件名)拼到同一条 latest/download 路径下;清单里
已写完整 http(s) 地址的原样使用。
- 网络全走 `core::download`,不新造栈:包体交给引擎 `download()`(镜像展开
→ 地区判定 → 健康度排序 → 退避 → 续传 → 原子落盘),清单走引擎的
`plan()` + 共享 client 逐候选取文本(与 `game::java` 的一锤子 GET 同一手法)。
两条路径都吃到 mirrors.json 与地区档案里生效的 gh-proxy 前缀。
- 可配置面只有 owner/repo(默认 AskaEth/Unlucky-Launcher)与 base(默认
https://github.com,测试指向本地假服务);渠道只有 stable 有清单,
beta/alpha/nightly 返回 Ok(None)(D50「先只发 stable」),清单 404 也算
「还没发布」而不是错误。
- `UpdateErrorKind` 新增 `Network`:远端取字节失败(连不上/超时/5xx/候选全挂)
与本地 IO 分开——前者可重试,后者重试无意义。引擎把逐源失败压成
AllSourcesFailed,本源从失败摘要里还原「所有源都 404」为 SourceMissing
(产物没上传不该被报成网络抖动)。
- 校验仍只有一处:包体请求只带 expected_size,长度/摘要双检留在
`update::verify`(与 DirSource 同口径)。
- 单测 13 条,全程离线(假 HTTP 服务在 127.0.0.1):固定清单地址、产物 URL
解析、自定义 base/owner/repo、清单 404/非 JSON/字段非法/渠道不符/5xx 各自
归到白名单分类、产物下载、产物 404 → SourceMissing、镜像优先下 gh-proxy
前缀(清单与产物都验)、与 DirSource 同清单同产物选择结果一致。
|
2026-11-07 08:06:22 +08:00 |
|
AskaEth
|
afdbc9fd51
|
Merge branch 'feat/m153-docsweep-close-forgotten-doc-findin'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-07 08:00:04 +08:00 |
|
AskaEth
|
7946e5b804
|
docs(readme,cli,packaging): M153 清账四条被排忘的文档类 finding
① README 两版下载表:linux-x64 / linux-arm64 / macos-arm64 / macos-x64 四行补「not yet published /
暂未发布」标记(与 M143 的 windows-arm64 行同款措辞),表后改成「本版只发布 windows-x64」的口径,
并说明发布 job 只留 PUBLISH_SLOTS 里的槽位(现住 release-publish.yml);顺带把「produced by the CI
matrix」那句改成「矩阵里有、默认发布跑不编、all_slots=true 才编来取证」。
② packaging/make_artifacts.py 两处 docstring 还写 windows-arm64 是 cross-built:按 M140 后的原生
windows-11-arm 事实改写。(release-notes.md 的同一说法在 M139/M142 已改掉,本次核实无残留,未再动。)
③ cli 缺 id 的 hint:删掉「(id 不进仓库)」并改成与 cli/help.rs 一致的「官方构建已内置、环境变量优先、
自建时构建期注入」;Secret 透传的事实留在同处代码注释。
④ README 两版文件清单表:release.yml 从「six-slot build / 六槽位构建」改成「两个 Windows 槽位原生
构建 → 只发布 windows-x64;all_slots=true 才整表六槽位取证」。
纯文案,不动任何构建或运行时逻辑。
|
2026-11-07 07:57:32 +08:00 |
|
AskaEth
|
5c96227881
|
Merge branch 'feat/m151-relmanif-generate-update-manifest-i'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-07 07:55:17 +08:00 |
|
AskaEth
|
f9607c1246
|
docs(packaging): M151 复审 P2-1 两处未决注释按 D51 定案改写(方案甲/六件套/v0.2.2 起适用)
|
2026-11-07 07:52:50 +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 |
|
AskaEth
|
87ab8783a3
|
Merge branch 'feat/m149-msabake-bake-approved-client-id-int'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-06 21:21:30 +08:00 |
|
AskaEth
|
5597a4cc18
|
feat(release,docs): M149 发布构建烘入微软登录 id(仓库 Secret),文档改为「官方构建开箱即用」
构建侧: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 通过。
|
2026-11-06 21:08:53 +08:00 |
|
AskaEth
|
1c53c29f76
|
Merge branch 'feat/m147-cifix-repair-ubuntu-red-checks-and'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-06 20:30:08 +08:00 |
|
AskaEth
|
166342b021
|
fix(core,design): M147 修掉 test(ubuntu) 剩下的两条红(M144 被 fail-fast 挡住没看见)
`cargo test --workspace --all-targets --no-fail-fast` 在 docker 里(Debian 12 / rustc 1.99.1)
第一次跑全:app-iced 那条修好后,还有两个 target 各有一条 **Linux 专有**的确定性失败——
M144 只看到第一条,因为 cargo 默认在第一个失败 target 就停。两条都是「夹具/断言按 Windows
语义写死」,不是产品逻辑错。
1. `unlucky-core`:`platform::wallpaper::windows::tests::current_theme_expands_local_app_data_env_var`
(crates/core/src/platform/wallpaper/windows.rs:286,460 passed / 1 failed)
夹具用了**混合分隔符**:`LOCAL_APP_DATA` 写 `C:/Users/u/AppData/Local`,而 `CUSTOM_THEME`
写 `C:\Users\u\AppData\Local\…`。探针把 `%LOCALAPPDATA%` 展开后拼上 `\Microsoft\…`,得到
`C:/Users/u/AppData/Local\Microsoft\…`;`FakeIo` 却按 `CUSTOM_THEME` 建键。Windows 的
`Path` 把 `/` 与 `\` 都当分隔符 ⇒ 两个 PathBuf 相等;Linux 不 ⇒ 查不到文件 ⇒ 0 个候选。
修法:`LOCAL_APP_DATA` 改成反斜杠原样(`r"C:\Users\u\AppData\Local"`),展开结果与
`CUSTOM_THEME` 逐字节相同。测试仍能在 Linux 跑,不丢覆盖(不是加 cfg 门躲开)。
2. `unlucky-design`:`color::palettes::tests::accent_on_fixed_neutral_only_moves_the_neutral_hue`
(crates/design/src/color/palettes.rs,162 passed / 1 failed)
`assert_eq!(Palettes, Palettes)` 做 f64 位相等,而两侧算中性色相的路径不同:一侧取
`NEUTRAL_HUE_DEG` 字面量,一侧经 `atan2()` 现算——glibc 与 UCRT 差 1 ulp
(239.51420577630955 vs …964)。这正是 palettes.rs:361-365 那条注释自己警告过的坑。
修法:把「固定中性色相」喂成**种子色相的实测值**(`per_seed.neutral.hue_deg()`),两侧同源
⇒ 断言保持**逐位相等**(比放宽容差更紧),零额外行。`NEUTRAL_HUE_DEG` 与种子色相的绑定仍由
隔壁 `neutral_hue_is_the_default_seed_hue` 用 1e-9° 容差钉着。
⚠️ 这里没有照 tower 建议的「1e-9° 容差逐项比」:那个写法在 rustfmt 下要多 9 行,而本文件正好
400 行、顶在 guards.yml 的红线上。改完 399 行(比改前还少 1 行)。
验证(命令与 ci.yml 逐字一致,容器 ull-linux-check:bookworm):
- `cargo test --workspace --all-targets --no-fail-fast` → **exit 0**(原 exit 101,2 targets failed)
- `cargo clippy --workspace --all-targets -- -D warnings` → exit 0
- Windows:`cargo test -p unlucky-core --lib` → 464 passed / 0 failed;
`cargo test -p unlucky-design --lib` → 163 passed / 0 failed(不回归)
|
2026-11-06 20:19:03 +08:00 |
|
AskaEth
|
fdb9ebb014
|
build(packaging): M147 新增 linux-check-docker.sh,本机复跑 ci.yml 的两条 ubuntu 门禁
`linux-smoke-docker.sh` 复刻的是 runtime-smoke(能不能真跑起来),本脚本复刻的是**编译期
门禁**(能不能编过 / 测过):`cargo clippy --workspace --all-targets -- -D warnings` 与
`cargo test --workspace --all-targets --no-fail-fast`,命令与 ci.yml 逐字一致。
为什么值得单独一条脚本:M144 的两条 ubuntu 红只在「Linux + --all-targets + -D warnings」
三件事凑齐时才炸,Windows 本机永远复现不了(那些 `#[cfg(target_os = "windows")]` 分支在
Windows 上都有使用者)。本脚本是「本机提前挡住它们」的唯一通道。
实现:在现成的 `ull-linux-smoke:bookworm` 上只加一层 `cmake` + `ninja-build`(`aws-lc-sys`
缺 cmake 编不过,M144 实测),缓存卷挂 `registry` 子目录(直接挂 /usr/local/cargo 会盖掉
镜像里的 cargo 本体,M62 踩过),Git Bash 路径用 `cygpath -m` 归一。
- `ULL_CHECK_STAGES`(默认 `clippy test`):两阶段各自跑完再汇总退出码,一处红不掩盖另一处;
`ULL_CHECK_FAIL_FAST=1` 恢复首错即停。
- `ULL_CHECK_TEST_ARGS`(默认照抄 ci.yml):快查用 `-p unlucky-app-iced --lib`。
- 每阶段打印 `<命令> → exit=<code>`,便于与 CI 注解里的码对照。
诚实边界写在脚本头:基础镜像 Debian 12 / runner Ubuntu 24.04,只对齐编译期判定,不覆盖
发行版差异面;也不跑 fmt / build / runtime-smoke。
M147 实测(本机 Docker / ull-linux-check:bookworm / 2026-11-06):
- `ULL_CHECK_STAGES=clippy` → exit=0(1m27s,原 14 条错)
- `ULL_CHECK_STAGES=test ULL_CHECK_TEST_ARGS='-p unlucky-app-iced --lib'` → 623 passed / exit=0
|
2026-11-06 20:07:04 +08:00 |
|
AskaEth
|
ae1410f342
|
ci: M147 给两个平台的 test 步加取证能力(--no-fail-fast + 注解 + 退出码回显)
三条红里 `test (windows)` 至今只有一个「Process completed with exit code 1」——而 cargo
自己的失败码是 101,那个 1 的来源不明(pwsh 包装层洗码 / 进程被杀,两说都未排除)。job log
要登录才能读(匿名 403),但**注解匿名可读**(GET /check-runs/<id>/annotations → 200)。
所以把一条 `cargo test --workspace --all-targets` 拆成两个平台的取证版本,各做三件事:
1. `--no-fail-fast`:cargo 默认第一个失败的 target 就停(M144 实测 Linux 只跑了 7 个 test
binary 就退),后面还有没有第二条失败完全看不到;
2. 失败时把 `error` / `failures:` / `test result: FAILED` / panicked 行升成 `::error::`
注解(`%` 转 `%25`,那是 workflow command 的保留字符)——拿不到 job log 时注解是匿名
侧唯一能取到的失败正文;
3. 显式 `echo "cargo exit=<code>"`,把「包装层把码洗成 1」「cargo 真失败(101)」「进程被杀
只给码、零诊断」三种情形分开。
两平台的码从哪来(不能混用):
- Linux 走 bash(默认 shell 带 `-e` + `pipefail`):先 `set +e` 再自己取 `${PIPESTATUS[0]}`
——那是 cargo 的码,不是 `tee` 的码;不关 `-e` 的话管道一失败就在 tee 之后退出,后面三行
永远跑不到。
- Windows 走 pwsh:`PIPESTATUS` 是 bash 语法,改用 `$LASTEXITCODE`(`Tee-Object` 是 cmdlet,
不会改它)。注解的正则不锚 `error:` 那一支,因为 pwsh 把原生 stderr 折成 ErrorRecord 后
行首可能多一截前缀,锚死会漏行。
两条都以 `exit <code>` 结尾,退出码不再经过管道传递。
|
2026-11-06 20:07:00 +08:00 |
|
AskaEth
|
8bfabafe8a
|
fix(app-iced): M147 修掉 Linux 侧 clippy 的 14 条错与写死平台的 α 断言
两条红的成因都是「Windows-only 的东西没有平台门」:Linux + `--all-targets` + `-D warnings`
三件事凑齐时,Windows 专有的 DWM/穿透代码在 Linux 上变成未用导入 + 死代码。
clippy(14 条错,docker 内 exit 101 → 0):
- dwm.rs `set_preference` 的 `#[cfg(not(windows))]` 分支以 `return` 结尾 ⇒ needless_return;
那个块本来就是该 cfg 下函数体的尾巴,去掉 `return`。
- dwm.rs 三常量 + 四读函数在非 Windows 上没有使用者(唯一调用方 `probe::run_one` 的
Windows 版被门着,`transparency.rs` 只 re-export 三项)⇒ dead_code。用**模块级**
`#![cfg_attr(not(target_os = "windows"), allow(dead_code))]`:
· 逐项 `cfg(target_os = "windows")` 会把它们从 Linux 构建里删掉,本文件那几条与平台
无关的单测(属性号照 Win32 头文件、无效句柄不许表现成成功)就连编译都过不了;
· 逐项 `cfg_attr` 要多 7 行,本文件 394 行 → 会顶破 guards.yml 的 400 行红线(现 398 行)。
代价写明在文件头:非 Windows 上本模块的 dead_code 不再报。
- exstyle.rs `use super::raw_ex_style`:唯一使用者 `click_through` 自己按平台门着 ⇒ 补 cfg。
- probe.rs 的 `use super::dwm::{…}`:`CornerOutcome` 与平台无关(`ProbeRow` 字段 + 非 Windows
的 `empty_row`),其余九个符号只服务于 Windows 的 `run_one` ⇒ 拆成两条 use。
- window_alpha.rs `use …RawWindowHandle`:只有 `RawWindowHandle::Win32` 那条臂用它 ⇒ 补 cfg。
test(docker 内 622 passed / 1 failed → 623 passed / 0 failed):
`opaque_or_refused_alpha_never_touches_the_window_style` 里「无效句柄 ⇒ Failed」是按 Windows
语义写死的;非 Windows 走 `transparency::set_layered` 的空实现,如实返回 `Unsupported`。
按平台拆成两条断言(Windows 断 `Failed`,其它断 `Unsupported`),两边都不许表现成
`Applied`/`Opaque`。顺带说明:`dispatch` 的 `layered=false` 那半条断言与平台无关,保留在
两条之外照跑。
验证(本机 Windows + Docker Debian 12,命令与 ci.yml 逐字一致):
- docker `cargo clippy --workspace --all-targets -- -D warnings` → exit 0
- docker `cargo test -p unlucky-app-iced --lib` → 623 passed / 0 failed
- Windows `cargo check -p unlucky-app-iced --all-targets` → 无 error/warning
- Windows `cargo test -p unlucky-app-iced --lib` → 624 passed / 0 failed / 2 ignored
|
2026-11-06 20:06:56 +08:00 |
|
AskaEth
|
2e16df0191
|
Merge branch 'feat/m145-pkgsplit-split-release-workflow-and'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-06 19:32:47 +08:00 |
|
AskaEth
|
f4cab82c65
|
ci(release): M145 复审 P2-2 修正过时上下文名(不可达分支的报错文案)
|
2026-11-06 19:30:10 +08:00 |
|
AskaEth
|
374e168334
|
docs(packaging): M145 按主题拆分 README(索引 + docs/,节号不变)
packaging/README.md 也是 400 行整,且安装包与自动更新马上要动发布线。按主题分成
「索引 + 5 份承载文件」,每份 ≤124 行:
- README.md 只留真相源声明、§1–§12 的索引表、§11、§12
- docs/artifacts-and-version.md:§1 产物矩阵 + §2 版本来源
- docs/build-and-ci.md:§3 怎么构建
- docs/runtime-deps.md:§4 运行时依赖 + §5 软渲染兜底
- docs/profiles-and-measurements.md:§6 构建档位 + §7 实测
- docs/compliance-support-boundaries.md:§8 合规 + §9 支持矩阵 + §10 已知边界
节号沿用原编号,所以全仓「packaging/README.md §N」式引用(根 README / README.zh-CN /
make_artifacts.py / release-notes.md / ci-runtime-smoke.md / release*.yml 注释)都不用改。
搬家由脚本按原文件切片生成,逐行可查:旧 README 400 行全部出现在新位置,唯一改写的
旧行是 §12 清单里那两行(文件清单必须反映拆分后实况)。新增行 15 条:索引段、§3 的
M145 说明、§12 的 5 份新文件行。
|
2026-11-06 19:29:47 +08:00 |
|
AskaEth
|
e3ee404bd5
|
ci(release): M145 把 release.yml 拆成编排 + 两个可复用工作流
release.yml 已是 400 行整,下一处改动必撞全仓行数红线(guards.yml 的 file-size)。
拆成「触发 + 槽位表 + 编排」的主工作流与两份 `workflow_call`:
- release-build.yml:原 build job 的 11 个步骤逐字搬过去,只有四个矩阵键换成同名
inputs(slot / os / build_dir / rustflags);矩阵仍由调用方 plan 生成并展开。
- release-publish.yml:原 release job 的 6 个步骤逐字搬过去(PUBLISH_SLOTS 白名单、
裁剪、重算 SHA256SUMS、渲染说明、create/edit 幂等);调用方只留 needs / tag 门禁 /
contents: write 的授予,token 走显式透传的 secret,pre-release 三态改读
github.event.inputs.prerelease(dispatch 的 boolean 输入无法表达「空值」)。
on / env / 顶层 permissions / concurrency 与 plan 的槽位表一字未动。
校验:YAML 可解析、actionlint 全仓零告警、12 段 run 脚本全部 bash -n 通过、
逐步骤比对(归一化后)与拆分前完全相同;120 / 233 / 151 行。
|
2026-11-06 19:29:47 +08:00 |
|
AskaEth
|
57082219ea
|
Merge branch 'feat/m146-updcore-update-core-without-binding'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-06 19:27:03 +08:00 |
|
AskaEth
|
2e718af711
|
feat(core): 新增 update 模块,做与更新源无关的自更新内核
更新源还没拍板,所以先把与源无关的那半边做掉:语义化版本比较、发布清单模型、
渠道准入、下载校验、原子替换 + 回滚。源抽象成 UpdateSource trait(清单 + 包体两个
方法),core 里没有任何 CDN 常量;内置的 DirSource 吃本地目录或 file://,既是测试
实现也是将来 HTTP 源的对照物。
取舍:
- 版本比较严格按 semver 2.0 §11:数值比(0.9 < 0.10)、预发布 < 同号正式版、
预发布标识逐段比(alpha < beta < rc 是 ASCII 序的自然结果,不另立阶段权重表)、
构建元数据不参与排序与相等。
- 渠道准入两道判据:清单自报渠道的阶梯比较 + 版本号里的预发布阶段。清单可能写错,
版本号不会,所以正式版渠道即使拿到一份自称 stable 的 rc 也不会提示更新。
- 校验两道判据且顺序有意:先比长度(抓截断,不必读全文件)再比摘要(抓内容错),
长度要求**恰好**相等;失败即删暂存文件。StagedPackage 只能由 stage() 产出,
于是「未校验的包」在类型上就进不了安装路径。
- 替换跨平台统一成「旧文件改名挪开 → 新文件搬进来 → 失败把备份搬回去」:Windows 上
覆盖运行中的 exe 不存在,改名是唯一可用动作,而改名也可能被不共享删除的句柄拒绝,
所以失败必须能回滚。Unix 也照这个顺序跑,避免回滚路径只有 Windows 被真正跑过。
- core 零 UI 依赖不变:只有 serde/serde_json + 复用的 sha1/sha2,无新依赖,
Cargo.toml 未改;不接 presenter、不接 UI。
单测 62 条(crates/core/src/update/tests/):版本边界、清单校验、渠道准入、
摘要不符、包体截断(短了/多了)、无权限写目标目录、Windows 占用文件、回滚与备份清理。
|
2026-11-06 19:16:15 +08:00 |
|
AskaEth
|
156abfe38b
|
Merge branch 'feat/m143-readmearm-mark-windows-arm64-as-not'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-06 12:35:48 +08:00 |
|
AskaEth
|
152e677b15
|
docs(readme): M143 下载表把 windows-arm64 标为暂未发布
依据 `.github/workflows/release.yml:291` 的 `PUBLISH_SLOTS: "windows-x64"`:arm64 槽位仍在
矩阵里构建取证,但不进 Release(同文件 300-313 行还会把白名单外的产物裁掉)。用户照旧表去下
`..._windows_arm64.exe` 会 404。
- 两版 README 的 Shape 列加「暂未发布 / not yet published」,行不删(架构支持意图仍在)
- 表后补一段可核的理由:CI 的 ARM64 runner 缺 Windows SDK 的 ARM64 导入库,已定位、在修;
并点明 PUBLISH_SLOTS 才是「进不进 Release」的开关,windows-x64 是当前唯一可下载的 Windows 资产
- 不写日期/版本承诺;windows-x64 命名规则与体量描述未动;packaging/README.md 与
release-notes.md 未碰
|
2026-11-06 12:35:11 +08:00 |
|
AskaEth
|
e4d8b75723
|
Merge branch 'feat/m142-xi64only-unblock-release-ship-x64-a'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-06 12:33:51 +08:00 |
|
AskaEth
|
a70e901bea
|
ci(release): M142 发布白名单只留 windows-x64 + 修掉诊断脚本在 -e 下先退出
1) PUBLISH_SLOTS 去掉 windows-arm64:白名单齐全性检查是「名单内少一档就 fail」,
arm64 连试四轮未成 ⇒ Release 永远 fail、x64 编成功也发不出去。arm64 仍留在矩阵里
照跑取证(诊断注解保留),红不挡发布;修好后把键加回这一行即可(一行可逆)。
2) 修 M141 自毁 bug:`shell: bash` 是 `bash -eo pipefail`,脚本里的 `set -uo pipefail`
关不掉 -e,于是 `vc_lib=$(find 不存在的根 | head -n1)` 被 pipefail 判非零后 errexit
当场退出,一条注解都没打(上一轮只剩 exit code 1)。现在显式 `set +e`、每处探测
`|| true`、问题记进 ERRORS、4 行实况快照无论齐不齐都先打完,再由显式 exit 定红绿;
齐全时快照降级为 notice(绿跑也留「探测没坏」的证据)。
3) 新增 arm64 失败收尾注解步骤(`if: failure()`),红在其他步骤时也能说清红在哪、不影响 x64。
4) packaging/README.md §1/§3/§4/§7.5/§9 与 release-notes.md 的 Downloads/Support matrix/
Install 同步为「当前只发布 windows-x64,arm64 待修」。
|
2026-11-06 12:30:07 +08:00 |
|
AskaEth
|
cc2ecd61e6
|
Merge branch 'feat/m141-arm64sdk-diagnose-and-fix-missing-a'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-06 12:18:57 +08:00 |
|
AskaEth
|
241a258e45
|
Merge branch 'feat/m140-arm64ci-make-windows-arm64-buildabl'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-06 12:00:01 +08:00 |
|
AskaEth
|
5678683561
|
fix(release): M140 r1 复审三条 p2 —— vswhere -find 单值、根因措辞、SDK 双根
P2-1(真缺陷):`-find` 是单值参数,老写法 `... "${find_args[@]}"` 一次传 4 个
`-find`,官方定位器只认其中一个(复现:last-wins 下取到 Hostx64),
所以 round-1 新加的「ARM64 优先 → Hostarm64」在 vswhere 分支上从未执行。
改成每个 pattern 各起一次定位器,不赌取值规则;注释同步为真话。
P2-2(措辞):README §4 不再声称 v0.2.1 那次是「x64 镜像缺库」——windows-2025
镜像清单里 VC.Tools.ARM64 与 SDK 26100 都在,根因未定论,更像自检的路径探测;
§7.4 的 dumpbin 门禁补一句覆盖 windows-latest 与 windows-11-arm 两个镜像。
P2-3(放宽):arm64 库体检的 SDK 侧也改成两个安装根(Program Files (x86) 与
Program Files),把「路径猜错 → fail-closed 误报」这个正是本次事故的形态再降一档。
行数:release.yml 400 / README 400(均 ≤400);PUBLISH_SLOTS 未动。
|
2026-11-06 11:59:31 +08:00 |
|
AskaEth
|
b27e86c65b
|
ci(release): M140 windows-arm64 改用原生 windows-11-arm runner
交叉编译路线在 CI 上从未成功过一次:v0.2.1 首次真跑即红在
「Windows ARM64 交叉工具链体检」(windows-latest 上探不到 VC/SDK 的
ARM64 库),故按文档标准 runner 表把 arm64 槽位改成原生
windows-11-arm(公开仓免费,4C/16G),产物回到 target/release。
- 槽位表:windows-arm64 os=windows-11-arm、build_dir=target/release;
无交叉槽位后 target 键与 rustup target add / cargo --target 一并删掉
- 体检步骤重写为「Windows ARM64 工具链体检」:失败时打印实际探测到的
VS 根、VC arm64 lib 目录、SDK 的 um/arm64 目录;SDK 不再只认
tail -n1 挑出的单一版本(全版本里找)
- dumpbin 定位链补 Hostarm64/arm64 分支,按 RUNNER_ARCH 选宿主工具族
(x64 上绝不挑 arm64 二进制),vswhere/find/PATH 三级与硬门禁不变
- packaging/README.md §1/§3/§4/§7.5 同步原生化与冒烟真跑的说法
|
2026-11-06 11:51:01 +08:00 |
|
AskaEth
|
1a290a15a3
|
Merge branch 'feat/m139-ciwin-trim-release-ci-to-two-window'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-06 11:39:14 +08:00 |
|
AskaEth
|
9de51e16af
|
ci(release): M139 发布 CI 只跑两个 Windows 槽位,整表六槽位改为手动取证
build 矩阵从六个槽位裁到 windows-x64 / windows-arm64 两个:
- 矩阵改由新增的 `plan` job 生成(`fromJSON(needs.plan.outputs.matrix)`),槽位表只在该
job 里有一份,`mode: ci` 默认编、`mode: probe` 只有 `all_slots=true` 才编;
- `workflow_dispatch` 新增 `all_slots` 布尔输入(默认 false = 只跑 Windows),
Linux/macOS 四档保留完整定义与打开办法(改 mode 一行),取证能力没删;
- `PUBLISH_SLOTS` 不变(两个 Windows 槽位);齐全性检查仍按下载下来的产物判,
白名单槽位没编/编挂就 fail,不会因矩阵变小而永远过;
- packaging/README.md §1/§3/§4/§9 与 release-notes.md 的 Downloads / Support matrix
同步成「四档默认不构建」,不留「六槽位都构建」的旧说法。
|
2026-11-06 11:33:52 +08:00 |
|
AskaEth
|
f617f60134
|
Merge branch 'feat/m137-rel021-bump-to-0-2-1-and-ship-windo'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-05 21:30:34 +08:00 |
|
AskaEth
|
54b81cbb7f
|
chore(release): M137 版本升到 0.2.1,发布只发两个 Windows 槽位
版本:`[workspace.package] version` 0.2.0 → 0.2.1,并把全部 intra-workspace path
依赖的 version 约束一并对齐(`"0.2"` → `"0.2.1"`,M121 的教训)。Cargo.lock 里只有
8 个 unlucky-* 成员条目变化。`crates/app` 是 workspace `exclude` 的 Slint 退役树(manifest
连解析都过不了),不参与解析,故原样保留。
release.yml:新增 `PUBLISH_SLOTS` 白名单(唯一开关)= `windows-x64 windows-arm64`。
六槽位一律构建取证,release job 先按白名单裁掉 Linux/macOS 四档产物再重算 SHA256SUMS,
所以 tag 触发的 Release 只有 4 个资产 + SHA256SUMS.txt。release job 改成
`always() && !cancelled()`:未验证槽位构建失败不连坐 Windows 发布,真正的门禁是白名单
齐全性检查。将来某槽位真机验过后把它加进那一行即打开。
顺手修掉一处从未生效的门禁:齐全性检查的 glob 用的是连字符形态
(`dist/$prefix-*-$slot*`),对 D49 之后的下划线资产名永远匹配不上,改成
`dist/${prefix}_*_${stem}*`。资产命名规则 / SHA256SUMS / 合规文本并列资产 /
`--version` 与 tag 交叉校验一律未动。
packaging/release-notes.md:清掉 v0.1.0 / Slint 时代的说明,Downloads 与 Support matrix
只描述本版实际发布的 Windows 两个槽位(其余标「built by CI, not published」)。
packaging/README.md §1/§3/§9 同步 gate(矩阵加「本版发布」列、§3 写清白名单与打开办法)。
起手顺带把示例 tag 从 v0.2.0 更到 v0.2.1,并把「winit / femtovg」更正为「winit / wgpu」。
|
2026-11-05 21:30:13 +08:00 |
|
AskaEth
|
a03e90fc1a
|
Merge branch 'feat/m138-readmepub-reshape-readme-for-the-pu'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-05 20:59:39 +08:00 |
|
AskaEth
|
a3f26d424b
|
docs(readme): r1 复审 P2 两条措辞修正(dry-run 口径、导入取消的真实含义)
P2-1:`--dry-run` 原来写成「file list, total size, source per file」,比实现强。人类
可读输出是按角色的文件数与字节数 + 合计 + 每类一个源链样本
(crates/cli/src/commands/install/report.rs:161-201),逐文件列源是被刻意否决的设计
(crates/core/src/game/install/plan_view.rs:46-49:「只取每类的首个文件做样本……逐文件
列源选择既没用也没法读」)。整份逐文件清单只在 --json 的 data["files"] 里。
P2-2:「安装是真取消」原来挂在整合包条目下,读者会读成「整合包导入也能真停」。实际
导入取消是界面级的:面板收回 + 结果作废,后台导入跑到底(crates/presenter/src/host/
addon/pack.rs:28-42 模块文档原话「取消是界面级的……core 的 ImportRequest 没有取消
令牌」)。真取消是版本安装那条路(crates/presenter/src/host/dispatch.rs:61-88:在飞
文件就地掐断、段边界收手、不登记实例),已移到「版本管理」条目。
中英两版同步改,未动结构。
|
2026-11-05 20:59:16 +08:00 |
|
AskaEth
|
8ad9792abd
|
docs(readme): 重排成面向第一次打开的人的次序,并补一张真截图
发布前把两份 README 的次序改成:一句话定位 → 截图 → 现在能用什么(含「还没做」)
→ 下载与运行 → 从源码构建 → 架构/模块地图 → 许可与致谢。原来的边界说明没删,
拉到对应功能旁边;「还没做」独立成节并写实。
同时按用户令清掉所有 v0.1.0 / Slint 时代的内容(版本考古段、历史 bin 行、Slint
Royalty-Free 义务段、crates/app 的模块地图行与构建说明、「翻牌还欠 bin 改名」)。
NOTICE 未动。
内容上纠正了几处「写得比实现强」:
- 启动器内的助手没有接真实模型(transport 是脚本化的),原句「chat 在启动器里」
会让读者以为能用;现在明说占位,并把真的那部分(MCP server)单独讲清。
- 「界面文案统一走一份目录」改成本地化边界:守门只扫实例页,且外观面板老控件
仍是硬编码英文。
- 实例页的 新建/导入/复制/打开文件夹/删除、日志页的 打开文件夹、设置帧的
保存/重置/加覆盖 都是没有后端的占位按钮(pages/mod.rs 偏离 #8),写进「还没做」。
- Java 回退链按地区不同,补上 java.vendorPriority 与区间差异。
- 补 ULL_CF_API_KEY(CurseForge 检索的前置,此前全仓文档都没提)。
截图:docs/images/instances-en-light.png(DevDocs/artifacts/m120/03-instances-en-light.png,
1180×760、浅色、英文界面;实例名与档案名均为测试数据,无路径/令牌)。
|
2026-11-05 20:53:30 +08:00 |
|
AskaEth
|
9cc3260644
|
Merge branch 'feat/m136-msadoc-update-docs-now-that-missing'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-05 20:13:33 +08:00 |
|
AskaEth
|
3bc6d76b84
|
docs(readme,release-notes): M136 缺 client id 的对外文案改成现行行为
M132 之后界面已经直接说「微软登录未配置 + 要设 ULL_MSA_CLIENT_ID」并刻意不给重试按钮,
而 README / README.zh-CN / release-notes 还写着「只会弹通用登录失败 + Code: other」——
那是修前行为。三处改成:标题/正文/Code: msa_not_configured/无重试,并保留「其余失败
仍只给分类文案 + 码,原文只进日志」这半句(那是真的,也是有意的)。
|
2026-11-05 20:10:10 +08:00 |
|
AskaEth
|
9dedaa6098
|
Merge branch 'feat/m132-msanotcfg-surface-missing-client-id'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-05 20:08:55 +08:00 |
|
AskaEth
|
119b49cf83
|
test(presenter): M132 烘焙了 client id 的构建里让入口锚直接红(r2 P2-1)
r2 复审实测:`ULL_MSA_CLIENT_ID=fake-0000-test-id` 构建 + 同一处变异 → `ok. 22 passed`。
原因是我上一条写成了 `if is_configured() { assert!(CLIENT_ID_BUILD.is_some_and(..)); return; }`
——`remove_var` 之后 `is_configured()` 等价于 `CLIENT_ID_BUILD` 非空,随后的 `assert!` 判的是
同一条件的反面,恒真、无失败路径,于是锚在那种构建里**绿着失效**。这正是本 mission 要防的
「守门空跑」形态,而我报告里还把它写成了「只允许是这个原因」,与代码不符。
改成 `if let Some(source) = client_id_status().source() { panic!(..) }`:环境变量摘掉后仍
报告已配置,就带着 `source=` 和两条出路(不带 id 构建 / 给 `resolve_client_id` 加接缝)直接
红,逼人做决定。没有 `#[ignore]`、没有开关;正常的「两处都没有 id」构建照旧跑两条真登录流。
验证(贴原生输出):
- 注入 id + 变异 → FAILED(panic,`source=Build`),旧代码此处是 `ok. 22 passed`;
- 注入 id + 无变异 → 也 FAILED(这才是重点:不是靠变异才红,而是拒绝空跑);
- 无 id + 变异 → `220 passed; 1 failed`,红的正是这条锚;
- 无 id 正常 → `221 passed; 1 ignored`。
|
2026-11-05 20:08:52 +08:00 |
|
AskaEth
|
f2149048fb
|
test(presenter): M132 把「缺 client id → 原因码」那行钉进测试(r1 P2-1)
复审 r1 实测:把 `start_login` / `start_browser_login` 里的 `auth_failure(&error)` 改回
`LoginFailure::Other`,编译通过、884 条测试全绿——也就是说「缺 id 会变成 MsaNotConfigured」
这件事此前只有代码可读。这条正是本 mission 要防的回退,补一条能抓它的锚。
新锚 `a_missing_client_id_reaches_the_login_panel_as_a_config_gap` 不只测 `auth_failure`,
而是**真的起两条登录流**(设备码 + 授权码),从 `JobSender` 收到的第一条 `HostTask::Login`
上断言 `failure == MsaNotConfigured`,并断言原文(含 `ULL_MSA_CLIENT_ID`)仍只在 `message`
里、页面画不出来。零网络:`from_env` 在 id 判定处就地早退,事件立刻到,不需要任何桩。
环境变量是进程级的,所以照 core 的做法串行 + panic 也还原;构建期注入过 id 的构建里
(本仓库 CI/本地都不注入)显式断言「只能是这个原因」后返回,不是 ignore/开关。
测试模块从 `accounts.rs` 拆成 `host/accounts/tests.rs`(`#[cfg(test)] mod tests;`,先例
`dto/accounts.rs`、`host/install.rs`):`accounts.rs` 400 → 299 行,拆完两边都远离 400 行硬线。
scope 已由塔台批准扩到 `crates/presenter/src/host/accounts/**`。
变异验证(最终代码上重跑):
- 两处 `auth_failure(&error)` → `LoginFailure::Other`:`221 → 220 passed / 1 failed`(只有新锚红);
- 还原:222 全绿。
顺手把 fn 指针数组换成一个 `assert_config_gap(name, start)` 辅助函数,
`cargo clippy -D warnings` 的 `type_complexity` 不放过它。
|
2026-11-05 20:08:52 +08:00 |
|
AskaEth
|
af39efd23b
|
fix(presenter,app-iced,i18n): M132 缺 MSA client id 上屏成「未配置 + 怎么补」
缺 client id 原来整条链路只给 `LoginFailure::Other`:界面画「Sign-in failed /
完整原因在启动器日志里 / Code: other」,用户得翻日志才知道要设 `ULL_MSA_CLIENT_ID`。
落点定在**账户页登录面板**,不是启动流程:这个失败只发生在 `microsoft_auth()`(两条
登录流的入口);没配 id 的发布版建不出微软账户,`identity::resolve` 那条启动路径用户
撞不到(只有「有 id 的构建里登录过、之后 id 被摘掉」才可达)。
- presenter:新增 `LoginFailure::MsaNotConfigured`(`msa_not_configured`)。`microsoft_auth`
改为回 `AuthResult`,`AuthError::Unsupported`(`from_env` 唯一的产出点,零网络)单独成码,
其余失败照旧走 `classify`。诊断原文仍只进日志。
- i18n:账户域新增 `AccountLoginNotConfigured`(标题)/ `AccountFailureMsaNotConfigured`
(正文:设 `ULL_MSA_CLIENT_ID=<id>` 或构建时注入,改完重启),golden 同步。
- app-iced:`failure_title_key` 给这一类专属标题;正文按码查表;这一类**不给「重试」**
(进程内的环境变量改不了,重试必然是同一个错)。
- 测试:`a_missing_client_id_tells_the_user_what_to_configure` 断言 UI 模型里出现「未配置」
+ 变量名 + `<id>` 占位 + `msa_not_configured`,且没有那句「去翻日志」;反向锚
`a_network_failure_does_not_look_like_a_missing_config` 与
`only_a_missing_client_id_becomes_the_config_gap_code` 钉住别的失败不许跟着变。
为什么这一类可以上屏:上屏的是 catalog 固定文案(无凭据、无 token、无内部细节),
`DevicePanel::Failed` 里没有 `message`/`detail` 字段,原文在类型上就画不出来;
理由是它的原因本身就是用户的下一步。M117/M119 的「诊断不上屏」约定不动。
|
2026-11-05 20:08:52 +08:00 |
|
AskaEth
|
01ca8033be
|
Merge branch 'feat/m135-deadlabel-drop-dead-launch-loader-l'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-05 19:15:59 +08:00 |
|
AskaEth
|
321617861a
|
chore(m135): 删掉死代码 launch::loader_label,修 M134 之后变假话的三处文档
M134 复审点名、且都在它 scope 外的收尾。
- `presenter/src/host/launch.rs::loader_label` 删除:全仓零调用点(唯一提及是
i18n 的一条注释),函数体逐字重复 `dto::LoaderKind::label()` 并硬编码「原版」——
它既是第二份显示词表,又绕过 i18n;留着等于给下一个人示范「照这样写就行」。
随之无用的 `LoaderKind` import 一并收掉。
- `presenter/src/lib.rs` 的 dead_code 豁免说明不再点名已删函数(否则那行注释指向
一个不存在的符号)。
- `i18n/src/bridge.rs:65` 注释改指向唯一那份显示词表(`dto::LoaderKind::label()`)。
- `core/src/game/loader.rs` 与 `presenter/src/dto/instances.rs` 两处「显示路径
没有守卫(已知缺口)」改成 M134 之后的真形态:显示路径是委派(拿 core 的稳定 id
反查 DTO 词表,没有手写 match 可糊),新种类先在 `dto::LoaderKind::from_core` 编
不过,糊错的后果由 `loader_kind_ids_are_the_released_contract` 与按 `ALL` 遍历的
`every_core_loader_kind_reaches_the_tile_as_itself` 钉住。
- `presenter/src/host/game.rs` 无需改动:M134 当时已把它的文档改成新形态,读下来是
真话(`dto_kind` 的 doc 与两个测试的 doc 都对得上现在的代码)。
验证:fmt --all --check 通过;`cargo test -p unlucky-presenter -p unlucky-i18n`
= i18n 29 passed / presenter 220 passed(1 ignored);clippy 两 crate --all-targets
`-D warnings` 零告警。删后全仓(含 workspace 外的 crates/app)已无
`launch::loader_label` 引用。
|
2026-11-05 19:09:53 +08:00 |
|
AskaEth
|
ffb608c854
|
Merge branch 'feat/m134-dtoshape-guard-the-presenter-displa'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-05 19:02:17 +08:00 |
|
AskaEth
|
c14543a112
|
fix(m134): 显示路径的 core→DTO 种类改成委派,不再留手写映射臂
M126 r3 复审实测:core 加第八家加载器、对外契约与 help 都补齐、只在
host::game::dto_kind 那一支写 `=> Vanilla`,三个 crate 全绿(402/220/42)
而磁贴静默显示「原版」——M122 修掉的用户可见 bug 复活。
- dto_kind 不再是自己一张七支手写 match:种类由 core 的稳定 id 反查 DTO 词表
(LoaderKind::parse → dto::LoaderKind::from_core,全仓唯一那份映射)。落笔处没了:
想糊 `=> Vanilla` 的人到这儿没有 match 可写,新种类必须先过 from_core。
- 反查不到(core 的 as_str 与 parse 自相矛盾,物理上做不到)就 panic,不退回「原版」。
- 测试从手抄七支清单换成按 core 的 ALL 遍历:加一家自动进圈,不用记得补一行。
|
2026-11-05 19:02:15 +08:00 |
|
AskaEth
|
fb44a264ee
|
Merge branch 'feat/m133-devguard-run-cheap-guards-on-dev-pu'
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Dev Guards / 架构与合规守门(同 main 口径) (push) Canceled after 0s
Dev Guards / fmt (rustfmt --check) (push) Canceled after 0s
Dev Guards / clippy (ubuntu) (push) Canceled after 0s
|
2026-11-05 18:15:40 +08:00 |
|
AskaEth
|
e0e1f90aed
|
ci(workflows): 让日常线 dev 也跑「快且会静默腐化」的守门
本仓日常开发线是 dev,日常合并不走 PR;而 ci.yml / guards.yml 只挂在
`push: branches: [main]` + `pull_request` 上 ⇒ fmt / clippy / 文件行数≤400 /
三条零依赖守门在日常线上一次都没跑过。可见后果:packaging/README.md 涨到 401 行
超全仓红线,直到文档普查才被发现(M131 才修回 398)。
做法(新增 dev-guards.yml,不改 main/PR 判据):
- guards 作业用 `uses: ./.github/workflows/guards.yml` 复用**同一份**六道守门脚本
(guards.yml 只加了 `workflow_call:` 触发,其余一字未动),避免两份 unsafe 词法器
各自演进造成「dev 绿、main 红」的双真相;
- fmt / clippy 各写一份,命令与 ci.yml 逐字一致(ci.yml 整份复用会把 build/test/
runtime-smoke 矩阵也拖上 dev);
- 刻意不上 dev:全量 cargo test(--all-targets 的 clippy 已覆盖「测试代码编译不过」
这类腐化,「断言暂时红」在施工中间态是常态)、build release、runtime-smoke。
成本控制:workflow 级 concurrency 取消同 ref 旧运行;clippy 在「本次推送只碰文档」
(*.md / LICENSE / NOTICE / .gitignore 白名单)时跳过编译,判据保守——非 push、
before 全 0、base 不可解析、diff 为空、出现任何白名单外路径一律照跑。
|
2026-11-05 18:15:37 +08:00 |
|
AskaEth
|
969d5ea450
|
chore(git): 从分支摘掉误入库的 .pyc 快照,并把 __pycache__/ 与 *.pyc 加进 .gitignore
03a5de9(TowerSpawn 的 WIP 快照)把主检出里未跟踪的
packaging/__pycache__/make_artifacts.cpython-312.pyc(18459 字节二进制)一并提交了。
这里用 git rm --cached + 忽略规则把它挡在主线之外:跑过 make_artifacts.py 就会再长
一次,不堵根因的话每次 spawn 都会重新污染主检出并触发 WIP 快照。
|
2026-11-05 18:15:36 +08:00 |
|
AskaEth
|
7764863142
|
tower: snapshot of uncommitted base checkout changes (worktree wt-133)
|
2026-11-05 18:15:34 +08:00 |
|
AskaEth
|
217c8ee19c
|
Merge branch 'feat/m126-loaderstr-unify-loader-kind-stable'
|
2026-11-05 18:09:06 +08:00 |
|
AskaEth
|
f6b7759aa8
|
docs(m126 r3): 收窄「唯一一份」的说法,并把 ③ 的承诺改成真话
纯文档,零逻辑改动(`git diff` 里每一行都是 `//!` / `///`)。
P2-1「唯一一份」不成立:`cli/src/cli/help.rs` 里 `ull help instances` 的词表行是
**会打印给用户看的第二份逐字副本**。四处说法收窄为「源头表在 core + 另一处逐字副本在
help.rs,由 `help_lists_every_stable_id` 按 `ALL` 遍历守着」:`game/loader.rs` 的模块
文档(原「生产代码里这七个串只有一处」)与 `as_str` doc(原「生产代码里唯一一份 id
字面量」)、`cli/commands/instances.rs` 的模块文档(原「全仓唯一一份 id 字面量」)与
`loader_json` doc(原「两样都只该有一份」)、`presenter/dto/instances.rs` 的 as_str doc
与契约测试 doc、`addon/loader/mod.rs` 的两处「唯一真相源」。
P2-2「③ 拦得住静默变原版」对显示路径不成立:`presenter/src/host/game.rs::dto_kind` 里
糊一支 `=> Vanilla`、同时把契约与 help 补齐,三个 crate 全绿而磁贴静默显示「原版」。
现在写的是「③ 拦的是**对外词表**(加种类、改词表都红),但**拦不住显示路径**,那处目前
没有守卫(已知缺口,另行记账)」。
顺带只做排版级的行数回收:loader.rs 400 → 397(≤400,仍留余量)。
门禁:cargo fmt --all --check → FMT_OK(本轮按要求只跑 fmt)。
|
2026-11-05 18:09:00 +08:00 |
|
AskaEth
|
14ac0dc248
|
test(m126 r2): 加一支枚举不更新对外契约现在必然红(集合断言 + help 守卫)
r2 复审指出「加一家加载器会被逼着表态」只做到一半:编译期只拦「漏 match」,三处消费方
用最省事的 `=> Vanilla` 糊过去既编得过、测试也全绿——新加载器会静默显示成原版,正是本
mission 要消灭的形态(r1 里「Rift 会红」是负样本名字撞上的巧合,不是守卫)。
- presenter 的 `loader_kind_ids_are_the_released_contract` 增加**第 ② 段**:把 core 的
`LoaderKind::ALL.map(as_str)` 与独立手写的七个 id 做**集合相等**比较。加一支而不更新
契约 → 红;改词表 → 红。(r1 删掉 `assert!(ALL.len()==7)` 后缺的正是这一环:数组宽度
只保证「表里那一行写成 7 个」,不保证枚举没多一支。)
- 新增 `cli::commands::instances::help_vocabulary_tests::help_lists_every_stable_id`:
按 `LoaderKind::ALL` 遍历 `ull help instances` 的词表行,漏写一个新 id 必红(此前
`help.rs:67` 那段词表没有任何测试,而旧的 `help_documents_the_loader_field_contract`
只查关键词,加一家新加载器时它照样绿)。
- `addon::loader::tests::vocabulary` 补 `installable_list_matches_the_from_core_mapping`:
把唯一还手写的 `LoaderKind::all()` 与 `from_core` 认可的集合对齐(不重抄字面量)。
- 模块文档第 ③ 步改成真话:契约测试会拦「改词表」与「加新种类」;但 `=> Vanilla` 这种
糊法**编得过**,拦住它的是那条集合断言,不是编译器(改名同理,只有契约测试会红)。
- 一并修掉 presenter 那条测试 doc 里指向已被删除的 `MARKERS` /
`markers_cover_every_kind_that_has_one` 的引用,改指向现在真实存在的守卫。
- loader.rs 从 398 压到 395(≤400,留 5 行余量;拆测试到子模块需要 scope 放宽到
`crates/core/src/game/loader/**`,超出本任务文件清单,已按规矩记账)。
验收实测(临时加 `Abyss` + 三处 `=> Vanilla` 糊过去,已还原):presenter 契约测试红
(left 8 项 / right 7 项),CLI help 测试红(漏了 `abyss`);core 往返测试与安装侧清单
守卫、CLI 的 `json_rows_*` 仍绿(它们本就管别的事)。
|
2026-11-05 18:08:59 +08:00 |
|
AskaEth
|
a322cfcbfe
|
refactor(core): M126 r1 返工:词表改由宏单表生成,安装侧解析收口
复审 r1 的三条:
P1(CI 会红):`const MARKERS: [(LoaderKind, &'static str); 6]` 触发
clippy::redundant_static_lifetimes(`error: constants have by default a 'static
lifetime`)。返工直接**删掉 MARKERS**:标记串就取 `LoaderKind::as_str()`,候选顺序取
`LoaderKind::ALL`,认不认标记看 `has_marker()`——解析表既没有独立字面量,也没有独立清单。
P2-1:「漏加 ALL 不会被任何东西拦住」是真话,之前的 doc 覆盖声明是假的。返工用
`loader_kind_vocab!` 宏从**一张表**一次生成枚举 / `ALL` / `as_str` / `has_marker`:
「加了一支却忘了进清单」在物理上不可能(没有第二份清单可写)。尺寸锚随之删除(`[Self; N]`
的宽度本来就由表决定),`parse` 留在宏外的独立 impl 里。
P2-2:「全仓唯一一份 id 字面量」原先不成立——安装侧 `LoaderKind::parse` 还手写了一份反向
匹配表,并带一个只进不出的 `neo-forge` 别名。返工让 install 侧 `parse` **委派**
`core::game::LoaderKind::parse`,只额外收 `neo-forge`(Modrinth 拼法)这一个输入别名,
并新增 `addon::loader::tests::vocabulary` 覆盖「委派没接错 + 别名只进不出 + 装不了的几家
返回 None」。
测试:core 的 `markers_cover_every_kind_that_has_one` 换成
`every_stable_id_parses_back_to_its_kind`(往返 + 顺序优先级),仍是「改名不可见、只有契约
测试能抓」的分工,doc 里写明。
门禁:fmt OK;clippy -p unlucky-core -p unlucky-presenter -p unlucky-cli --all-targets
-- -D warnings 干净;三 crate 测试 core lib 401 / presenter 220 / cli 41 全 ok。
文件行数:loader.rs 397(≤400)。
|
2026-11-05 18:08:57 +08:00 |
|
AskaEth
|
be37c17962
|
refactor(core): M126 加载器稳定 id 词表收敛到 game::LoaderKind::as_str
M122 把「id → 加载器」的解析收到 core::game::loader::InstanceLoader::parse,但
「种类 → 对外稳定 id」的命名词表还散在多处,其中 install 侧那一份只靠一句「不要改名」
的注释约束,MARKERS 更是第四张无守卫字面量表。
- core::game::LoaderKind 新增 as_str(**全仓唯一一份 id 字面量**)、has_marker
(穷尽 match:新种类必须表态认不认 id 标记)、parse(as_str 的反查)与 ALL(清单,
顺序即标记优先级);MARKERS 的标记串改为取自 as_str,不再是独立字面量。
- addon::loader::LoaderKind::as_str 改成委派(结构映射,无字面量):安装侧拼出的
<mc>-<kind>-<loader> 与解析侧从此同源。
- presenter::dto::instances::LoaderKind 的 as_str/parse 委派给 core(to_core/from_core
是结构映射),删掉第四份词表;CLI 删掉 loader_kind_id 翻译层,直接调 core。
- 测试:core 新增 markers_cover_every_kind_that_has_one(MARKERS↔ALL↔has_marker↔as_str
逐格对齐 + 按标记串 round-trip + neoforge 先于 forge);presenter 新增
loader_kind_ids_are_the_released_contract(七个 id 逐字钉住 + 反查 + 别名隔离)。
- 对外输出未变:真二进制对同一组 7 类实例的 `instances list --json` 输出逐字节相同
(md5 0341752658ca28e020ba48c31a51a124),人读输出同样逐字节相同。
file 行数:core/game/loader.rs 337→399(≤400 硬约束,文档按密度重排、事实未丢)。
|
2026-11-05 18:08:56 +08:00 |
|
AskaEth
|
84f85bbc79
|
Merge branch 'feat/m130-readmedoc-fix-readme-claims-about-c'
|
2026-11-05 18:05:41 +08:00 |
|
AskaEth
|
72ee57f0a8
|
docs(readme): M130 r1 修正产物名的槽位说明与自相矛盾的 GUI 二进制称谓
- P2-1:`[.exe]` 只对两个 Windows 槽成立,四个 Linux/macOS 槽是 .tar.gz
(make_artifacts.py:76-82 SLOTS、:243 stage_archive;packaging/README.md §1)。
三处产物名统一写成 `unlucky-launcher_<version>_<platform>_<arch>` + 按槽位说明形态。
- P2-2:删掉「`unlucky-launcher` once extracted or downloaded」与段尾「Windows 裸资产文件名带
版本段」的互相拆台;改成归档解出叫 `unlucky-launcher`、Windows 裸资产叫
`unlucky-launcher_<version>_<platform>_<arch>.exe`。中英同步。
|
2026-11-05 18:05:39 +08:00 |
|
AskaEth
|
95131d856e
|
docs(readme): M130 补微软登录的 client id 前提,删「十四页」计数,把 i18n 守门边界与产物名写成实测口径
- Accounts:发布版二进制不含 Azure 公共客户端 id(CI 0 处注入),需设 ULL_MSA_CLIENT_ID;
没配时点登录只拿到通用「登录失败 / Code: other」。
- 删「feature-complete: fourteen pages」:代码里 Route 8 个变体、Screen::ALL 5 个,没有读法得到 14;
改成按 Route 列举并说明 Screen::ALL 为何更小。
- i18n:删「视图层没有硬编码字符串」,改成白名单守门抓英文、中文与其它页扫不到的已知边界。
- 自报名例子改成 argv[0] 实测口径;翻牌措辞区分「cargo bin 名未翻」与「产物名已翻」。
- 中文版补「一壳两形」highlight,账户与 auth 模块行补第三方社区服 / 本地档案。
- 顺手改掉「ull 能跑在 Termux」:Linux 资产 glibc ≥ 2.35,Termux 不在发布矩阵内。
|
2026-11-05 18:05:38 +08:00 |
|
AskaEth
|
7092469f90
|
Merge branch 'feat/m131-packdoc-shrink-packaging-readme-fix'
|
2026-11-05 18:03:23 +08:00 |
|
AskaEth
|
592f0c26f6
|
docs(packaging): M131 压回 400 行内,删 Slint 遗留祈使句/软渲染块,修 smoke 脚本 bin
- packaging/README.md 401 -> 398 行(回归 file-size 红线内)
- §5 删 SLINT_BACKEND=winit-software 命令块;现役入口改注 iced 的 --software-renderer
- §8 删「关于页保留 AboutSlint、不得移除」两句祈使句,只留 v0.1.0 资产事实段
- §7 抬头标明连字符产物名属哪次实测(现名形态写下划线 0.2.0),§7.3/§7.5 同步标注
- §11 删「该脚本现在会失败」的过期提醒,记录 M131 真跑证据
- linux-smoke-docker.sh: --bin/产物路径/target 全改 unlucky-launcher-iced(cargo clean -p 同步改
unlucky-app-iced,原来的 unlucky-app 已被 workspace exclude、清不掉陈旧产物)
|
2026-11-05 18:03:20 +08:00 |
|
AskaEth
|
5b217ae32d
|
Merge branch 'feat/m129-relnotes-rewrite-release-notes-to-c'
|
2026-11-05 18:01:29 +08:00 |
|
AskaEth
|
5a9d67530a
|
docs(packaging): M129 r1 P1-1 —— MSA 那段改成 GUI 现有行为,不再写「界面会告诉你怎么配」
复审 r1 把链路走了一遍:core 缺 id 早退(零网络)成立,但 presenter 的 fail() 只把原文
eprintln 进日志,事件只带原因码 Other;账户页据此画通用横幅「Sign-in failed」+「Code: other」,
完整原因在日志里。LaunchMsaNotConfigured 那条 i18n 目前只有定义/单测/golden,GUI 零调用点。
所以上一版「the app says "not configured" (with the command to fix it)」是把设计意图写成了现有行为。
改成分段如实描述:无 id 时在联网之前就停;GUI 显示通用横幅 + Code: other(原因在日志);
`ull accounts add msa` 会打出可照抄的修复命令(map_auth_error 的 hint,含变量名与 cargo build)。
另按 r1 P2-1 给 macOS 补 shasum 校验行(sha256sum 不是 macOS 自带)。
|
2026-11-05 18:00:55 +08:00 |
|
AskaEth
|
59eefdb052
|
docs(packaging): M129 发布说明重写到现行事实(下划线资产名 / MSA client id / 删 Termux 下载引导)
资产名全部改成 make_artifacts.py::asset_stem() 的 `名字_版本号_平台_架构`(下划线):
六行矩阵、ull 资产、tar 包名与解压出的顶层目录、PowerShell 校验命令。旧的连字符名
按文档下载会 404(D49 2026-11-05 改名,文档没跟)。
删掉「微软登录等 Mojang 白名单审批」整条(白名单 2026-11-03 已批准并真机验签),
换成真缺口:发布版不带 Azure 公共客户端 id,要 ULL_MSA_CLIENT_ID(环境变量或构建期
注入),未配置时界面说「未配置」而不是静默失败。不写任何 id 值。
Termux:删掉「下 ull 资产」的引导(ull 的 Linux 资产是 glibc 版,Android/bionic 上跑
不起来),矩阵行只留「构建自源码、GUI 未验证、不在本发布矩阵」。
顺带清掉三处过期陈述:Windows 数据根(原文说有 `portable.marker` 就便携、否则落
%APPDATA%——实际 portable 是默认模式,首次运行在 exe 旁建 .ULL/ 与 .minecraft/);
CLI 子命令表漏了 `pack import`;arm64 行里的内部决策编号 D21。124 → 107 行。
|
2026-11-05 17:54:18 +08:00 |
|
AskaEth
|
494a45fe12
|
Merge branch 'feat/m127-shotci-make-pixel-guards-actually-r'
|
2026-11-05 17:39:59 +08:00 |
|
AskaEth
|
02c7910ad5
|
ci(app-iced): M127 把下载页四条像素守门接进 CI(仅 Windows),缺图在 CI 里从 SKIP 改成失败
- 新增 tests/options_shot/feed.rs:四条断言共用一条「喂图」策略
· CI(CI 已设置)且 Windows 上缺 ULL_DL_*_SHOT ⇒ 失败并提示「守门未喂图」
· 非 Windows 上喂了图 ⇒ CI 里也失败(断言按 Segoe UI 标定的行高/墨迹宽度)
· 本机缺图仍可跳过,但每次都留一句提示
- ci.yml 的 test 作业(Windows 槽):pages_demo 现出 ready700/chips700/compact736/wide1180
四张图 → 写进 $GITHUB_ENV → cargo test -p unlucky-app-iced --lib options_shot
出图与断言两步都带 if: runner.os == 'Windows';失败时上传四张图便于复盘
- 顺带订正五处文档数字:main 7 整行 / r1 4 整行 / r2 7 整行,并写清第 8 条墨迹是 hint
(rows.rs ×3、options_shot/ready.rs、tests/view.rs),不动任何断言期望值
|
2026-11-05 17:17:43 +08:00 |
|
AskaEth
|
631d4647dc
|
Merge branch 'feat/m125-railfix-chips-tier-crushed-list-and'
|
2026-11-05 17:05:05 +08:00 |
|
AskaEth
|
0f26ed3753
|
fix(app-iced): M125 r2 —— chips 档「还没选版本」不再对半切;宽度表换成实测值
r1 复审 p2-1:`TailShare::of` 只判档位,于是 chips 档「刚进页面」(面板只有一行
提示)也被五五分——700×760 下列表 8 个版本只显示 4 个、下半块 ≈160px 空画布,
而修前(main)这一态是 7 整行。修法:判据加**面板形态**,`Hint` 在任何档位都钉死,
`Chips` + `Options`/`Install` 才共享。实测回到 7 整行(与 main 同一水位)。
守门:新增 `options_shot/ready.rs`(`ULL_DL_READY_SHOT`,不设 `ULL_DL_DEMO` 出的
700×760 图):列表区至少读出 6 个版本号。它在 r1 的图上**红**(4 个,原生输出见
mission 报告),在修后图上绿(7 个)。三条旧守门照旧(chips / compact / wide),
chips 与 compact 换修前图仍红。
r1 复审 p2-2:宽度表的实测值改正(同一张 736 图逐项量):
`1.21` 26(余 6)、`1.20` 28(余 4)、`24w` **29**(余 3)、`All versions` 墨迹画到
x=247(裁切边 248,只差 1px)⇒ 桶标签余量是 **3~6px** 而不是 6;「短标签『全部』= 32
零余量」这条论证的对比强度随之写准(比桶标签的 3~6px 更薄)。
`rails/major.rs` 的表格、`options_shot/compact.rs` 的测试文档一并改成实测值;
「墨迹右边界」那条反例也从 216..244 改成实测 216..247。
r1 复审 p3-1:第二级「全部版本」的图标从网格(与第一级同字形同药丸、像素级同形)
换成文档/清单字形 `IconKind::Logs`,理由与「图标集里没有版本/历史字形」写进
`major_shape` 文档。
r1 复审 p3-2:chips 档最多三层滚动(列表 / 面板 / loader 菜单)作为**已知风险**
登记在 `install.rs` 文档里,并写明为什么「把实例名移出滚动区」本轮不做(要拆
`options::section`,动三个文件,而且改完仍无法验证滚轮冒泡——没有通道)。
|
2026-11-05 16:43:35 +08:00 |
|
AskaEth
|
9c623a6fd3
|
style(app-iced): M125 拆文件时留下的孤儿文档片段(clippy 的 empty_line_after_doc_comments)
|
2026-11-05 16:03:10 +08:00 |
|
AskaEth
|
70dea995b7
|
refactor(app-iced): M125 主版本栏与选项区像素守门各拆一层(守 400 行红线)
两处拆分,只为过 `gate::every_source_file_stays_under_the_line_limit`:
- `download/rails.rs` 435 行 → `rails.rs` 311 + `rails/major.rs` 157:主版本桶那一栏
(`major_rail` / `major_entries` / `major_shape` / `MajorEntry` / `MajorShape`)搬进子模块,
`rail_title` 留在父模块(两条栏共用)。`Key::VersionMajorTitle` 的落点跟着搬,
`tests/i18n.rs` 的死 key 扫描表补上 `rails/major.rs`(漏扫会把活 key 判成死 key)。
- `tests/options_shot.rs` 475 行 → 345 + `options_shot/chips.rs` 75 + `options_shot/compact.rs` 67。
顺带修 `options_shot::bands()` 的一处既有缺口:它按三栏算列表列左缘(112+0+24+0+24 = 160),
chips 档没有侧栏时这个左缘是错的,右缘跟着冲出画面 22px——M125 的 chips 守门正好踩到
「扫描越界读到下一行像素」,`first_rule_y` 因此恒返回 None。现在 chips 档直接取页左缘
(112),三栏三档的数值一个不变(M123 那些 140/140、缝 24 的断言照旧)。
守门实跑(本机,tiny-skia):
- 解 ignore 的 `chips::a_chips_tier_shot_…` 在修后图绿、**修前图红**(实测 18px ≠ 44);
- `compact::a_compact_tier_shot_…` 修后图绿、修前图红(实测 44px 文字行 ≠ 40px 图标按钮);
- chips 那条换深色图同样绿(断言不依赖主题色)。
|
2026-11-05 16:01:03 +08:00 |
|
AskaEth
|
822f98022d
|
fix(app-iced): M125 chips 档列表不被选项区压成缝;Compact 档主版本首项不再裁字
两条缺陷都是 M123 取证时在真图上拍出来的,塔台另行核过图:
缺陷 1(medium):chips 档(窗口 < 736,可用宽 < 600)里选项区按内容高
≈316px 钉在列表下面,列表只剩 18px(0.4 行,行高 44)——版本号读不出来、
换不了版本。修法:`rows::TailShare` 两档,chips 档改成「列表与面板各吃一半、
面板自己可滚」(列表拿到 ≈182px = 4 整行,面板顶端那个实心「安装」与五个
loader chip 仍在屏内);三栏三档照旧钉死(760 高下列表还有 3 整行、面板
整块在屏内,两样都对)。判据按档位而不是按高度:页面模型里只有 window_width,
窗口高度没接进页面(边界写进 TailShare 文档与报告)。
缺陷 2(medium):Compact 档主版本栏宽 64,`ListItem` 两侧内边距各 16 ⇒ 文本格
32,首项「All versions」要 ≈84 ⇒ 图上只剩「All v」;中文「全部版本」= 4 全角字
= 64,32 里只剩「全部」且正好顶到裁切边。修法:图标条档的「全部版本」不画文字,
改画与本页第一级那个「全部」同一个网格图标(40×40 Tonal 药丸 + 全称 tooltip);
桶标签(1.21/24w,实测墨迹 26)放得下,照旧画原文。`rails.rs` 那条「64 宽里
1.21 仍完整」的注释改成实测宽度表,并写清它对首项不成立。
顺带:列表与尾部面板之间补上分隔线(三态一致),`rows::content` 与两个装配点
按档位传 `TailShare`。
守门:
- `tests/options_shot.rs` 解掉 M123 那条 `#[ignore]`(期望值一个字没改,只加
「列表区 ≥ 3 整行」与「面板仍在屏内、没被底边切」两条);
- 新增 `a_compact_tier_shot_draws_an_icon_for_the_first_major_entry`:缺陷 2 的
像素守门(首项是 40×40 居中药丸,不是 64×44 通栏文字行)。复审建议的
「墨迹右边界 ≤ 栏右内边界」在坏图上也是绿的(修前墨迹 216..244,边界 248),
所以改钉形状,理由写在测试文档里;
- `tests/rails.rs`:中文与英文都走 Icon 分支、以及 32px 文本格的宽度账
(「全部版本」= 64 > 32 是精确值,「全部」= 32 零余量所以不选短标签);
- `tests/view.rs`:档位 → TailShare 的决策面 + 两个装配点都按档位传。
未改产品文案、未改窗口最小宽、未动 M123 的任何断言期望值。
|
2026-11-05 15:48:57 +08:00 |
|
AskaEth
|
df0e98d811
|
Merge branch 'feat/m123-evidshot-close-three-acceptance-evi'
|
2026-11-05 15:46:28 +08:00 |
|
AskaEth
|
4a41263357
|
test(app-iced): M123 安装选项区 × 三栏同屏的宽度与行裁剪守门
安装选项区(`download/options`)与三栏(`download/rails`)各自都有断言,
但它们**同屏**这件事从来没验过:选项区一高列表就矮,窗口一窄两条栏一收列表
就窄,这两种挤压都不会让任何既有断言变红。
- `tests/options_screen.rs`:七档宽度(1180/1024/900/880/812/736/700)× 三种
选项态(原版 / Fabric / NeoForge 不兼容)。三栏数字按 `layout/rails.rs` 的
数值表逐格钉死;列表列在每一档都 ≥ 424(行内四样仍在一行);两条栏与选项
面板在同一份模型里、树能一次构建。
- `tests/options_shot.rs`:真 PNG 上的像素断言(需 `ULL_DL_OPTIONS_SHOT`)。
两栏同屏且像素宽度 = 裁决值 140/140、栏间 24 的缝真空着、第一行版本行整行
44px、选项区最后一行墨迹离底边还有余量。另有一条 `#[ignore]` 的 Chips 档
回归:700×760 下列表被压成 18px(现状红,缺陷已单列报告与 finding)。
出图(38 张)在 `DevDocs/artifacts/m123/`(git 忽略,不入库);旧的
`DevDocs/artifacts/m109/`(内容库页早于 M108 改名,导航轨写的是 `Download`)
已按任务 ② 删除,内容库 12 态在 m123 里按当前 tip 重出。
不动产品行为:本提交只有测试与模块声明。
|
2026-11-05 15:46:26 +08:00 |
|
AskaEth
|
c25e85b461
|
Merge branch 'feat/m124-cliloader-expose-parsed-loader-in-i'
|
2026-11-05 15:37:02 +08:00 |
|
AskaEth
|
9ead4ae892
|
feat(cli): M124 instances list --json 补 loader 字段,只加不改
`ull instances list` 的人读输出历来只逐字打 `version_id`,脚本/agent 要判断
「这是不是 Fabric」只能自己猜 id 形状——正是 M122 收敛掉的第二份真相。本提交只补
输出面:
- 每行实例加 `loader: {"kind": <稳定 id>, "version": <版本段>}`,解析一律调
`unlucky_core::game::InstanceLoader::parse`(M122 的全仓唯一入口),CLI 里没有
任何新的 id 匹配;CLI 只做「种类 → 稳定 id」的穷尽翻译。
- 原版恒为 `{"kind":"vanilla","version":""}`:键恒存在、不为 null,脚本不必判空。
- `kind` 是识别口径(7 值,含只能继承不能安装的 optifine/liteloader),不是
`install --loader` 的安装口径(5 值)——这条连同「vanilla 只表示 id 里没有加载器
痕迹」一起写进模块文档与 `ull help instances`(`--json` 是事实对外契约,字段说明
跟着契约走)。
- 向后兼容:`data.instances[]` 原有七个键一个没动,人类可读输出逐字不变。
- 测试(`commands::instances::tests`,走真入口 `crate::run`):四家自家 id + 原版 +
两家第三方前缀的真值表、原版非 null 的反向锚、人读输出与旧字段不变的兼容锚、
help 里有契约说明的文档锚。
|
2026-11-05 15:23:37 +08:00 |
|
AskaEth
|
e4b819a4cc
|
Merge branch 'feat/m122-loaderid-fix-loader-from-id-to-reco'
|
2026-11-05 15:06:50 +08:00 |
|
AskaEth
|
081ce65596
|
fix(core): M122 版本 id → 加载器只留一份解析,并认全自家 id 口径
`presenter::host::game::loader_from_id` 只认 `fabric-loader-…` / `quilt-loader-…`,
而本启动器自己生成的 id 是 `<mc>-<kind>-<loader>`(`1.20.4-fabric-0.16.5` /
`1.20.4-quilt-0.27.0`),于是刚装好的 Fabric / Quilt 实例在实例页显示成「原版」。
- 新增 `core::game::loader`:`InstanceLoader::parse` 是全仓唯一的 id 解析入口
(按 `-` 切段、段前缀匹配标记、跳过独立的 `loader` 段、砍老 HMCL 的 MC 尾巴)。
覆盖自家四种口径(生成端 `addon::loader::LoaderKind::version_id`)、老 HMCL / CF
口径、OptiFine / LiteLoader 第三方前缀;标记按整段前缀匹配,不再用「包含子串」。
- presenter 只留 DTO 翻译:`dto_kind` 穷尽 match(`dto/` 里仍不许出现 core 类型)。
- 测试:真值表**从生成端取 id**,反向锚(普通版本 id 不被认成加载器),映射单射,
以及端到端快照(`instances()` 的磁贴数据对四个加载器各自的版本号与徽标)。
|
2026-11-05 14:46:22 +08:00 |
|
AskaEth
|
829bd9043c
|
Merge branch 'feat/m121-verbump-0-2-0-workspace-version-and'
|
2026-11-05 14:08:39 +08:00 |
|
AskaEth
|
bf6b0c4126
|
build(release): workspace 版本 0.1.0 → 0.2.0,README 的 tag 事实改成 v0.2.0 口径
- Cargo.toml [workspace.package] version = 0.2.0;Cargo.lock 由 cargo 重新解出一致
(只有 8 个 unlucky-* 成员条目变动,第三方版本一字未动)
- 各 crate 的 `unlucky-*` path 依赖 `version = "0.1"` 同步提到 "0.2",否则工作区
根本解析不出来(cargo metadata 会报 `failed to select a version for
unlucky-core = "^0.1"`);crates/app 虽被 exclude、cargo 不读,也一并跟上避免将来
重新纳入时立刻解析失败
- core::launch::LauncherConfig 兜底的 launcher_version 改成 env!("CARGO_PKG_VERSION"),
不再是把版本写死一份(CLI / presenter 本来就这么写)
- README.md / README.zh-CN.md:删掉「v0.1.0 是目前唯一的 tag / the only tagged release」
这类随 v0.2.0 发布即变假的陈述,改写成「v0.1.0 是最后一个 Slint 版 tag,v0.2.0 是
重写后的第一个 tag」;所有讲 v0.1.0 资产 / Slint Royalty-Free 义务的历史记录原样保留
- packaging/README.md:命名与校验示例跟当前 tag 走(v0.2.0);§7 实测记录里的 0.1.0
输出加一句「属实测记录、不回填」,并把过期的「四个 workspace member」改成「任何一个」
|
2026-11-05 14:08:37 +08:00 |
|
AskaEth
|
7235cf08e4
|
Merge branch 'feat/m120-insti18n-instance-page-and-stage-la'
|
2026-11-05 13:36:55 +08:00 |
|
AskaEth
|
d0a8f68607
|
docs(m120): 页面模块的守门说明改成白名单口径
|
2026-11-05 13:36:45 +08:00 |
|
AskaEth
|
f86be2bd38
|
fix(app-iced): M120 r1 —— 徽标判据改回「类型是原版」;旧串黑名单翻成白名单
r1 复审 p2-1(真回归,我引入的):`loader_badge` 把「非原版 + 空版本号」也送进了
`Key::LoaderVanilla`。而 `host::game::loader_from_id("1.20.1-forge")` 这类 id 取不到版本段
(它按 `forge-` 找,id 却是 `-forge` 结尾),`LoaderInfo::badge()` 对它们给的正是品牌名
`Forge` / `NeoForge` / `OptiFine` —— 于是这三个显示成「原版 / Vanilla」。
判据改成「**加载器类型本身是原版** ⇒ 过词表,其余交给 `badge()`」:
- 修的是判据,不是加分支:函数注释本来就写着「只有原版这一支要过词表」,代码与注释相矛盾。
- 新回归测试 `the_loader_badge_keeps_the_brand_when_the_version_is_missing`:
`1.20.1-forge` / `1.20.1-neoforge` / `1.20.1-OptiFine` 三条 id 各断言列表副文案与 LOADER
卡的值都是品牌名(中英两套语言各跑一遍,品牌名两套语言相同)。
变异实测:把判据改回旧写法 ⇒ 立刻红(`left: "1.20.4 · Vanilla" / right: "1.20.4 · Forge"`,
与复审给的实证逐字相同)。
r1 复审 p2-2(不阻塞,按塔台要求顺手做):源码反扫从**黑名单 29 条旧串**翻成**白名单**。
- 先数过:五个页面源码里一共 13 个字面量,其中带 ASCII 单词的只有 6 条,全是专有名词 /
技术标识 / 占位符名 / 族名前缀(`{date} {time} UTC` / `isolated` / `shared` / `pid` /
`reason` / `Instances`),逐条写了理由。
- 判据反过来之后,往页面里**新写**一句英文也会红(复审抓到的哑点)——变异实测:
写进 `"Ready"` ⇒ 红;写回 `"ALL INSTANCES"` ⇒ 红。
- 反向锚保留:扫描器必须真扫到 ≥6 条、`Texts::of(` / `Header::new(texts.title())` /
`Key::Instances` / `Key::InstancesStage` 必须在用(防止断言空转)。
|
2026-11-05 13:36:45 +08:00 |
|