补齐跨渠道产物隔离核对并把 dev-mac 缺陷钉到字节级
Project CI / AI game creator shell Rust crates (push) Failing after 1m11s
Project CI / AI game creator shell Rust smoke (push) Successful in 1m59s
Project CI / AI game creator shell Rust lane 2/2 (push) Has been cancelled
Project CI / Frontend tests (push) Has been cancelled
Project CI / Repository checks (push) Has been cancelled
Project CI / Backend tests (push) Has been cancelled
Project CI / AI game creator shell web tests (push) Has been cancelled
Project CI / AI game creator shell Rust lane 1/2 (push) Has been cancelled
Project CI / Native shell tests (push) Has been cancelled
Project CI / AI game creator shell Rust crates (push) Failing after 1m11s
Project CI / AI game creator shell Rust smoke (push) Successful in 1m59s
Project CI / AI game creator shell Rust lane 2/2 (push) Has been cancelled
Project CI / Frontend tests (push) Has been cancelled
Project CI / Repository checks (push) Has been cancelled
Project CI / Backend tests (push) Has been cancelled
Project CI / AI game creator shell web tests (push) Has been cancelled
Project CI / AI game creator shell Rust lane 1/2 (push) Has been cancelled
Project CI / Native shell tests (push) Has been cancelled
- check:agc-update-channel-manifests:新增「不同渠道更新包不得字节相同」断言(需 AGC_UPDATE_VERIFY_DOWNLOAD=1),并核对 Windows 安装包文件名带本渠道产品名 - 只读核对 dev-win/dev-mac/release-win/release-mac:dev-win 0.1.154、release-win 0.1.150、release-mac 0.1.139 身份与版本一致;dev-mac 0.1.142 与 release-mac 0.1.139 的更新包 sha256 相同,字节级证明 dev 分区放了 release 渠道的产物 - 渠道安装身份隔离里程碑补本轮核对(发布产物身份 + 跨渠道唯一性),真机并存仍待验收 - macOS 里程碑与 pitfalls、decision-log 记录字节级取证与新断言
This commit is contained in:
@@ -63,6 +63,8 @@
|
||||
- 清单自洽的部分(都 PASS):`version=0.1.142`、`pub_date=2026-09-24T11:35:31Z`、`commit=c07c10c0c`;`platforms` 只有 `darwin-aarch64`(符合 2026-09-21 单架构决策);更新包对象 315,510,533 字节与 `.sig` 420 字节都存在,清单签名与 `.sig` 文本一致;下载后字节数一致、用 `tauri.conf.json` 里烘焙的 updater 公钥验签通过(`alg=ED`、`keyId=cb883447e3e87c4e`);首装 DMG `陶泥儿开发版_0.1.142_aarch64.dmg` 存在。
|
||||
- **两处真 FAIL**:把更新包解开看 `Contents/Info.plist`,里面是 **`CFBundleShortVersionString=0.1.139`**(清单写的是 0.1.142)和 **`CFBundleIdentifier=world.genarrative.ai-game-creator.release` + `CFBundleName=陶泥儿 Release`**(本渠道应为 `world.genarrative.ai-game-creator` / `陶泥儿开发版`),产物文件名也叫「陶泥儿 Release.app.tar.gz」。
|
||||
- 结论:`dev-mac` 渠道当前给 arm64 客户端提供的更新包是**旧版本 + 另一个渠道身份**的包。这既让「升级后版本没变」成立,也可能把 release 身份的应用装到 dev 渠道用户机器上,违反渠道安装身份隔离约定。第 1 条保持未勾选。
|
||||
- **字节级佐证(2026-09-28 补)**:`dev-mac/0.1.142/陶泥儿 Release.app.tar.gz` 与 `release-mac/0.1.139/陶泥儿 Release.app.tar.gz` 的 sha256 完全相同(`1dfc9deb79f7fa5fd66d8a8a47b80e3a6ff125b8762cabfd32d3e16dec946e4e`)。也就是说 dev 分区里放的就是 release 渠道那一次构建的产物,不是「版本号抄错」。
|
||||
- 对照:`release-mac` 自己是对的(`0.1.139` + `world.genarrative.ai-game-creator.release` / `陶泥儿 Release`),`release-win`(0.1.150)与 `dev-win`(0.1.154)的产物名与签名核对也都通过。核对脚本现在还会断言「不同渠道的更新包不得字节相同」,修复前这条会精确报出 `dev-mac = release-mac`。
|
||||
- 根因与修复(本轮已落地,见 decision-log 2026-09-28 条目):
|
||||
- 根因:`build-macos-ci.mjs` 之前只删「本轮要写的文件名」,构建目录里上一轮遗留的 `陶泥儿 Release.app.tar.gz` 不会被清掉;而 `generateUpdateManifest()` 是**扫描目录按优先级挑产物**,于是挑走了那个残留文件。
|
||||
- 修复:构建前按后缀清空 `macos/` 下的 `*.app.tar.gz`、`*.app.tar.gz.sig`、`*.dmg`、`*.dmg.sha256`;构建后读产物 `Contents/Info.plist` 断言版本与渠道身份;生成清单后再断言清单选中的就是本轮更新包。守卫逻辑在 `apps/ai-game-creator-shell/scripts/macos-release-identity.mjs`,单测 `macos-release-identity.test.mjs` 用线上那份 0.1.139 release 身份包做回归(`node --test` 59 passed,含新增 6 条)。
|
||||
|
||||
@@ -47,3 +47,14 @@
|
||||
|
||||
- `node --test apps/ai-game-creator-shell/scripts/build-release.test.mjs apps/ai-game-creator-shell/scripts/release-oss.test.mjs apps/ai-game-creator-shell/scripts/prepare-macos-codex.test.mjs apps/ai-game-creator-shell/scripts/cargo-features.test.mjs`:**60 passed / 0 failed**,含「release / beta 的 Windows 与 macOS 构建只写自己渠道分区、不能写 dev 桥」四条分区隔离用例。
|
||||
- 仍未执行:真实渠道打包(需要签名私钥与发号/上传授权)、双渠道真机并存安装、macOS 构建节点实跑。
|
||||
|
||||
## 本轮核对(2026-09-28,已发布产物的渠道身份只读核对)
|
||||
|
||||
发布产物已经在 OSS 上,可以用只读脚本核对「渠道身份是否真的落进产物」,不用等到真机安装。`npm run check:agc-update-channel-manifests`(`AGC_UPDATE_CHANNELS=dev-win,dev-mac,release-win,release-mac AGC_UPDATE_VERIFY_DOWNLOAD=1`)结果:
|
||||
|
||||
- `dev-win`(0.1.154,commit `76cdb96c5`):文件名 `陶泥儿开发版_0.1.154_x64-setup.exe`、对象存在、`.sig` 与清单一致、公钥验签通过 → 默认渠道身份不变。
|
||||
- `release-win`(0.1.150,commit `5c648ab9c7`):文件名 `陶泥儿 Release_0.1.150_x64-setup.exe`、签名与摘要核对通过 → 非默认渠道用独立产品名。
|
||||
- `release-mac`(0.1.139,commit `87e52860a7`):清单只登记 `darwin-aarch64`(符合 2026-09-21 决策);解出更新包内 `Info.plist` 是 `world.genarrative.ai-game-creator.release` / `陶泥儿 Release` / `0.1.139`,与清单版本、渠道身份一致。
|
||||
- **`dev-mac` 有真实缺陷**:清单 `0.1.142` 指向的更新包解出来是 `world.genarrative.ai-game-creator.release` / `陶泥儿 Release` / `0.1.139`,而且与 `release-mac/0.1.139` 的产物**字节完全相同**(`sha256=1dfc9deb79f7…`)。也就是说 dev 分区里放的其实是 release 渠道那份包,渠道隔离在这一次发布上被破坏(签名字段都是真的,只有身份和版本错了)。根因是 mac 构建目录残留产物被清单扫描挑中,已在 2026-09-28 修复(构建前清空同类产物 + 构建后断言包内版本与渠道身份),需要用修好的 mac 管线重发一次 `dev-mac`。
|
||||
- 新增的跨渠道断言:同一次核对里不同渠道的更新包不得字节相同(`1dfc9deb79f7: dev-mac/darwin-aarch64 = release-mac/darwin-aarch64` 就是修复前会命中的形态)。
|
||||
- 仍未勾选:真机上同时安装 `dev` 与 `release`、各自原地更新。上面这些只证明「产物身份正确」,不代替真机并存验收。
|
||||
|
||||
@@ -9706,6 +9706,7 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
|
||||
- 决策(构建期失败关闭):mac 发布入口在构建前按后缀清空 `macos/` 下的 `*.app.tar.gz`、`*.app.tar.gz.sig`、`*.dmg`、`*.dmg.sha256`;构建后读 `.app/Contents/Info.plist`,断言 `CFBundleShortVersionString` 等于本轮发布版本、`CFBundleIdentifier`/`CFBundleName` 等于该渠道安装身份;生成清单后再断言清单选中的更新包就是本轮那一个。任一不符直接中止,不写 OSS。
|
||||
- 决策(产物选择器本身也要挡旧版本):`generateUpdateManifest()` 是共享入口,Windows 侧靠 Jenkins 的 `git clean -fdx` 才没踩到同一个坑,所以再补一道与平台无关的守卫——`assertArtifactVersionMatches()` 要求文件名里出现形如 `_0.1.154_` 的版本段时必须等于本轮版本(残留的 `_0.1.153_` 安装包会被挑中并因此失败关闭);macOS 的 `<产品名>.app.tar.gz` 不含版本段,返回 `null`,由 mac 入口的身份断言负责。
|
||||
- 决策(只读核对也要看包内身份):`check:agc-update-channel-manifests` 在 `AGC_UPDATE_VERIFY_DOWNLOAD=1` 时下载 mac 更新包、解出 `Info.plist` 做同样断言;同时按 2026-09-21 决策断言 mac 渠道只登记 `darwin-aarch64`(不再要求 universal 双键)。
|
||||
- 决策(跨渠道产物不得同字节):同一次核对里若下载到多个渠道的更新包,脚本会断言它们的 sha256 两两不同——不同渠道的 `productName` / `identifier` 不同,产物就不可能相同。事故取证:`dev-mac/0.1.142` 的更新包与 `release-mac/0.1.139` 的更新包 sha256 都是 `1dfc9deb79f7fa5fd66d8a8a47b80e3a6ff125b8762cabfd32d3e16dec946e4e`,字节级证明 dev 分区放的是 release 渠道那次构建的产物。全量核对用 `AGC_UPDATE_CHANNELS=dev-win,dev-mac,release-win,release-mac AGC_UPDATE_VERIFY_DOWNLOAD=1`(约 950 MiB 下载)。
|
||||
- 决策(口径回归):macOS 现行契约是 arm64 单架构(2026-09-21 决策),里程碑里「两个 macOS 平台键指向 universal 产物」的旧文字按现行决策改写;不得据此重新切回 universal,除非按该决策给出的恢复路径补齐按架构的 Node 运行时。
|
||||
- 影响范围:`apps/ai-game-creator-shell/scripts/build-macos-ci.mjs`、新增 `apps/ai-game-creator-shell/scripts/macos-release-identity.mjs` 与其 `.test.mjs`、`apps/ai-game-creator-shell/scripts/prepare-macos-codex.test.mjs`、`jenkins/Jenkinsfile.ai-game-creator-shell-macos-build`、`scripts/check-agc-update-channel-manifests.mjs`、两份里程碑与本文件、pitfalls。
|
||||
- 验证:`node --test apps/ai-game-creator-shell/scripts/*.test.mjs` → **110 passed / 0 failed**(其中定向批次 `macos-release-identity / prepare-macos-codex / verify-updater-signature / build-release / cargo-features` 60 passed;新增的 mac 身份回归用例直接喂线上那份 0.1.139 release 身份 plist,必须抛错;新增的产物版本守卫用例喂 `_0.1.153_` 残留安装包,必须抛错);`npm run check:production-ops`、`check:encoding`、`check:doc-index`、prettier、eslint、`git diff --check` 通过;只读核对对线上 `dev-win` 全 PASS(含 158 MiB 产物下载验签与旧协议 sha256 一致),对线上 `dev-mac` 精确报出上面两条 FAIL。
|
||||
|
||||
@@ -6103,6 +6103,6 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/`
|
||||
|
||||
- **现象**:线上 `https://agc-dev.oss-rg-china-mainland.aliyuncs.com/agc/dev-mac/latest.json`(`version=0.1.142`、`commit=c07c10c0c`)把更新包指向 `陶泥儿 Release.app.tar.gz`;下载解开看 `Contents/Info.plist`:`CFBundleShortVersionString=0.1.139`、`CFBundleIdentifier=world.genarrative.ai-game-creator.release`、`CFBundleName=陶泥儿 Release`。同一份清单的首装 DMG 却是 `陶泥儿开发版_0.1.142_aarch64.dmg`。也就是说签名是真的、对象也在,但**版本与渠道身份都是错的**。
|
||||
- **根因**:`build-macos-ci.mjs` 以前只 `rmSync` 「本轮要写的确切文件名」,构建目录里上一轮(或其它渠道身份)留下的 `*.app.tar.gz` 不会被清;而 `generateUpdateManifest()` 是**扫描构建目录、按优先级挑产物**(同名优先级再按字典序),于是挑走了残留的 release 身份包。mac 构建机是复用 workspace 的,这类残留会长期存在。
|
||||
- **判据**:只读核对要**打开产物看身份**,不能只看「地址存在 + 签名匹配」。`npm run check:agc-update-channel-manifests`(`AGC_UPDATE_VERIFY_DOWNLOAD=1`)现在会解出 mac 包的 `Info.plist`,断言「包内版本 == 清单版本」且「包内 identifier/产品名 == 本渠道身份」;本轮对线上取样得到两条 FAIL,正是这个缺陷。
|
||||
- **判据**:只读核对要**打开产物看身份**,不能只看「地址存在 + 签名匹配」。`npm run check:agc-update-channel-manifests`(`AGC_UPDATE_VERIFY_DOWNLOAD=1`)现在会解出 mac 包的 `Info.plist`,断言「包内版本 == 清单版本」且「包内 identifier/产品名 == 本渠道身份」,并额外断言**不同渠道的更新包不得字节相同**;本轮对线上取样得到三条 FAIL,正是这个缺陷。字节级佐证:`dev-mac/0.1.142/陶泥儿 Release.app.tar.gz` 与 `release-mac/0.1.139/陶泥儿 Release.app.tar.gz` 的 sha256 完全相同(`1dfc9deb79f7…`),说明 dev 分区里放的就是 release 那一次构建的产物。
|
||||
- **处理(2026-09-28 已修)**:构建前按后缀清空 `macos/` 下的 `*.app.tar.gz`、`*.app.tar.gz.sig`、`*.dmg`、`*.dmg.sha256`;构建后读 `.app/Contents/Info.plist` 断言版本/identifier/产品名;生成清单后再断言 `release.artifact` 就是本轮那一个。守卫在 `apps/ai-game-creator-shell/scripts/macos-release-identity.mjs`,回归用例直接用线上那份 0.1.139 release 身份包(`node --test` 59 passed)。
|
||||
- **教训**:凡是「按目录扫描挑产物」的发布步骤,都要么先清空同类产物、要么按本轮预期路径断言;只删「本轮要写的名字」等于把上一轮的坏包留在候选集里。现在共享入口 `generateUpdateManifest()` 也补了与平台无关的 `assertArtifactVersionMatches()`(文件名带 `_0.1.153_` 这类版本段时必须是本轮版本),所以即使将来某个流水线不再 `git clean -fdx`,旧安装包也会被拒绝而不是被发出去。还有一条更一般的:核对线上清单时,先看 decision-log 的现行口径(这里 macOS 已是 arm64 单架构),别拿过期里程碑文字当契约。
|
||||
|
||||
Reference in New Issue
Block a user