同步 CI 镜像 tag 与文档口径,并补上工具链一致性护栏
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 17s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Failing after 11s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Failing after 14s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Failing after 12s
Project CI / AI game creator shell Rust smoke (pull_request) Failing after 11s
Project CI / AI game creator shell Rust crates (pull_request) Failing after 10s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / Native shell tests (pull_request) Failing after 10s
Project CI / Frontend tests (pull_request) Failing after 5s
Project CI / Repository checks (pull_request) Failing after 11s
Project CI / AI game creator shell web tests (pull_request) Failing after 11s

- 将 CI job 镜像默认 tag 从 genarrative/gitea-project-ci:20260807.1 升为 20260920.1
- 将 Dockerfile 两处 org.opencontainers.image.version 统一为 2026.09.20.1(原先一处 2026.07.23.1、一处 2026.08.07.1,后写的覆盖先写的)
- 同步 deploy/container/README.md 与开发运维文档中的镜像归档示例名
- 订正 pitfalls.md 中 CI 镜像的 Rust 版本,并记录 number_of_links 在 1.98.1 上实测仍未稳定
- 在 decision-log.md 追加本次 Rust 工具链升级到 1.98.1 的决策条目
- 在 scripts/project-ci-workflow.test.ts 新增一致性用例:镜像版本段、digest 与 tag 必须与 rust-toolchain.toml 及两份运维文档一致
This commit is contained in:
2026-09-20 17:06:49 +08:00
parent e1c8edd6bf
commit a35cdcc68c
7 changed files with 83 additions and 8 deletions
@@ -8986,3 +8986,13 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
- 决策:`pick_local_project_directory` 增加可选 `title`(限 24 字符、无控制字符,其余回退默认标题),使「选择项目创建目录」不再冒用「选择游戏项目目录」文案。
- 关联规范:`docs/project-memory/plans/【实施计划】AGC项目创建目录可选-2026-09-17.md``docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md`
- 验证:`cargo test --bin genarrative-ai-game-creator-shell creation_root`(2 项)、模板库定向单测 14 项、偏好模型 3 项、`appSurface` 472 项(含设置页「工作区」选择/恢复目录与「设置里选目录后建项带 `projectsRoot`」两条场景)、`tsc``check:encoding``check-doc-index` 通过。
## 2026-09-20 Rust 工具链升到 1.98.1:仓库侧四处同步 + runner 镜像必须重建
- 背景:macOS 27CLT for Xcode 27.0)冷构建时 proc-macro dylib 被链接成畸形 Mach-O`mis-aligned LINKEDIT string pool`),上游 rust-lang/rust#157750 已修复,而仓库锁的 stable `1.96.0` 仍复现(Issue #431)。
- 决策:根 `rust-toolchain.toml` 的 channel 由 `1.96.0` 改为 `1.98.1``deploy/container/gitea-ci-job.Dockerfile` 的 Rust stage 由 `rust:1.96-bookworm@sha256:19817ead…` 换成 `rust:1.98-bookworm@sha256:93ce27a88655056a51dbdd8f5f2d7ddc071c7b0070fb288a37b5a285fc83971e`(按 registry 配置实测该 digest 的 `RUST_VERSION=1.98.1`,与 channel 逐字一致)。
- 决策(版本标签):镜像 tag / label 一并从 `20260807.1``2026.08.07.1` 升为 `20260920.1``2026.09.20.1`(同一次核对发现 Dockerfile 里有两处 `org.opencontainers.image.version`:一处 `2026.07.23.1`、一处 `2026.08.07.1`,后写的覆盖先写的,本次一并统一为 `2026.09.20.1`)(`scripts/gitea-ci-job-image.sh``deploy/container/gitea-ci-job.Dockerfile`),`deploy/container/README.md` 与开发运维文档同步 digest、Rust 版本和归档示例名。镜像内容变了却沿用旧 tag,排障和回滚都会认错版本。
- 不变口径:镜像继续 `RUSTUP_AUTO_INSTALL=0`job 现场不下载工具链;`scripts/check-gitea-ci-job-image.sh` 仍按 `rust-toolchain.toml` 的 channel 逐字校验镜像内工具链名,所以基础镜像的 `RUST_VERSION` 必须与 channel 完全相同。`std::os::windows::fs::MetadataExt::number_of_links`rust-lang#63010)在 `1.98.1` 上实测仍未稳定,`#[cfg(windows)]` 侧继续使用自行声明 `ByHandleFileInformation` 的实现。
- 新增护栏:`scripts/project-ci-workflow.test.ts` 增加一条一致性用例——Dockerfile 的 `ARG RUST_IMAGE` 版本段必须等于 `rust-toolchain.toml` 的 channel 主次版本、其 digest 必须同时出现在两份运维文档里、镜像 tag 日期戳必须与 Dockerfile 的 `org.opencontainers.image.version` 一致,避免本次这种「改了 Dockerfile 忘了文档」的漂移。
- 待办(不在本次仓库改动内):在 station 上执行 `build / verify / export / load-runner`,备份 runner config 后把 `genarrative-ci` 映射切到新 Image ID 并 `docker restart --timeout 660 gitea-runner`;内层只有 1.96 时 PR 的 job 必然失败。macOS 与 Windows AGC 构建机(`jenkins/Jenkinsfile.ai-game-creator-shell-build`preflight 只校验 rustc/cargo 是否存在)需确认已装 `1.98.1`,macOS 冷构建是本次问题的原始验证目标。`deploy/container/api-server.Dockerfile``FROM rust:1.93-bookworm` 是另一处未加 digest 的 Rust 版本 pin,本次未动。
- 验证:分支 `chore/rust-toolchain-1-98` / PR #432`npx vitest run scripts/project-ci-workflow.test.ts``npm run check:encoding``git diff --check` 通过。Windows`1.98.1``npm run agc:build -- --debug` 的前端构建、Rust 编译与 NSIS 安装包生成成功(见 PR 描述记录);macOS 与镜像重建后的 CI 结果仍待验证。
@@ -360,7 +360,7 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/`
## 2026-08-15 `#[cfg(windows)]` 里的代码不参与 Linux CI 编译,CI 绿不代表能构建
- 现象:把 master`9f5c84ee7`)合进 `feat/five_min_design` 后,`cargo check --all-targets` 在 Windows 上直接 `error[E0658]: use of unstable library feature 'windows_by_handle'`,位置是 `apps/ai-game-creator-shell/src-tauri/src/project/manifest.rs``metadata.number_of_links()`。该文件与 `origin/master` **逐字节相同**,即 master 自身在 Windows 上就构建不过。
- 原因:`std::os::windows::fs::MetadataExt::number_of_links` 至今未稳定(rust-lang#63010,而 `rust-toolchain.toml` 锁的 stable `1.96.0`。引入它的提交是 `578f8019f`(优化 AGC 项目入口并识别 Godot 工作区),其中 unix 分支用 `MetadataExt::nlink()`(已稳定)、windows 分支用了未稳定的对应物。**Linux CI 上 `#[cfg(windows)]` 整块不参与编译,所以 CI 全绿。**
- 原因:`std::os::windows::fs::MetadataExt::number_of_links` 至今未稳定(rust-lang#63010;当时 `rust-toolchain.toml` 锁的 stable `1.96.0`2026-09-20 升到 `1.98.1` 后在同一台 Windows 机器上用该 stable 实测仍报 `error[E0658]: use of unstable library feature 'windows_by_handle'`(见 decision-log 同日条),因此本条的处置口径不变。引入它的提交是 `578f8019f`(优化 AGC 项目入口并识别 Godot 工作区),其中 unix 分支用 `MetadataExt::nlink()`(已稳定)、windows 分支用了未稳定的对应物。**Linux CI 上 `#[cfg(windows)]` 整块不参与编译,所以 CI 全绿。**
- 更普遍的形状:只要一段代码只在某个 `#[cfg(target_os)]` 下编译,它就完全绕过了其它平台的 CI——不只是 unstable feature,还包括类型错误、借用错误、缺失 import。跨平台分支是「双写」,两侧都得有人真的编译过。
- 处理:本仓库对「文件是不是无硬链接普通文件」统一自行声明 `ByHandleFileInformation` 并调用 `GetFileInformationByHandle`,见 `runner/endpoint.rs``tool_plan_handoff/storage_windows.rs``project/agent_db.rs``git_inspect.rs``image_inspect.rs``agent/generation/canvas_generation.rs``manifest.rs` 当前已采用同一实现,并保留 fail-closed 语义:无法取得句柄信息或确认存在硬链接时均拒绝,同时拒绝 directory / reparse point。
- 验证:改后 `cargo check --offline --all-targets` 通过、`cargo fmt --check` 通过、`project::manifest` 与 godot 相关定向测试 65 passed / 0 failed。判断「是不是本次合并引入」的通用手法:`git diff origin/master -- <file>` 为空即说明该文件就是 master 原样,问题不在合并。
@@ -4630,7 +4630,7 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/`
- 现象:`Repository checks``Frontend tests``Backend tests``Native shell tests` 都从全新 job 容器开始,apt、setup-node、rustup 和原生系统库在不同 job 里重复安装;后端与原生壳的安装时间可达数分钟,并把软件源和代理瞬时失败放大为四份。
- 原因:Gitea Actions job 彼此隔离,上一个 job 在容器内安装的包不会自动进入下一个 job;把同一套不随 PR 变化的工具链写在 workflow step 中,必然每次重做。
- 处理:用 `deploy/container/gitea-ci-job.Dockerfile` 预装 Node 22、固定 npm、Rust 1.96`rustfmt`、Chrome、`bwrap``rg``ffmpeg``clang/lld` 和 Tauri / 后端系统依赖,并按锁预热唯一根 npm workspace、server-rs、桌面壳与 AI 游戏创作壳 Cargo 四份下载缓存。四个 job 统一 `runs-on: genarrative-ci`,先用镜像内脚本直接从 Gitea checkout,再以 runtime 模式运行 `scripts/check-gitea-ci-job-image.sh`,同时检查四份缓存锁、工具链、完整 bwrap 与 Chrome headless。`RUSTUP_AUTO_INSTALL=0``rust-toolchain.toml` 变更时先重建镜像,不把下载 fallback 放回 job。
- 处理:用 `deploy/container/gitea-ci-job.Dockerfile` 预装 Node 22、固定 npm、Rust 1.98.1`rustfmt`、Chrome、`bwrap``rg``ffmpeg``clang/lld` 和 Tauri / 后端系统依赖,并按锁预热唯一根 npm workspace、server-rs、桌面壳与 AI 游戏创作壳 Cargo 四份下载缓存。四个 job 统一 `runs-on: genarrative-ci`,先用镜像内脚本直接从 Gitea checkout,再以 runtime 模式运行 `scripts/check-gitea-ci-job-image.sh`,同时检查四份缓存锁、工具链、完整 bwrap 与 Chrome headless。`RUSTUP_AUTO_INSTALL=0``rust-toolchain.toml` 变更时先重建镜像,不把下载 fallback 放回 job。
- 依赖边界:每个 job 仍必须各自执行 `npm ci`,让当前 lockfile 和 PR 依赖在干净环境中验证;区别是命中镜像 cache 时只做本地解包,锁新增依赖时才走受控网络。不要把 `node_modules` 或 Cargo `target` 烘进镜像,也不要向不受信任 PR 挂载跨 job 可写 cache。
- 锁漂移边界:runtime 校验输出任一 `*_cache_lock=partial` 说明镜像内 lock 与当前 checkout 不同,不代表新增依赖已经缓存;必须同时输出 Actions warning,提示可信分支落地后刷新镜像。必须在新镜像中对 server-rs、桌面壳和 AI 游戏创作壳当前 lock 执行真实 `cargo fetch --locked --offline``cargo metadata --no-deps` 不会证明依赖 archive 可用,不能作为替代。
- 构建网络边界:`CARGO_NET_RETRY` 只覆盖部分 crate 下载,registry `config.json` / index TLS 握手仍可能直接终止整次 fetch。Dockerfile 对每个 `cargo fetch --locked` 再做最多 5 次整命令级有界重试,最终仍执行断网 fetch,不能降低为无锁重试或省略离线闭合验证。
@@ -310,7 +310,7 @@ CI job 镜像由 `deploy/container/gitea-ci-job.Dockerfile` 定义:Ubuntu job
```bash
bash scripts/gitea-ci-job-image.sh build
bash scripts/gitea-ci-job-image.sh verify
bash scripts/gitea-ci-job-image.sh export /仓库外受控路径/genarrative-gitea-project-ci-20260807.1.tar.zst
bash scripts/gitea-ci-job-image.sh export /仓库外受控路径/genarrative-gitea-project-ci-20260920.1.tar.zst
bash scripts/gitea-ci-job-image.sh load-runner
```