From f6d230ce44c5e0ad15bb7b8bb9af659659b74c5d Mon Sep 17 00:00:00 2001 From: speak-agent <248744407+speak-agent@users.noreply.github.com> Date: Sun, 6 Sep 2026 02:18:47 +0800 Subject: [PATCH] docs(release): the index bump PR is machine-authored, and the pin waits on the pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two defects on 2026-09-05 came from the same step of the release tail, and neither was visible to this repository's CI. A hand-written index PR (xim-pkgindex#764) landed ahead of the generated one. It appended each platform table's new ["latest"] line instead of replacing the existing one, so every table carried two ["latest"] keys. A Lua table constructor takes the last assignment, which resolved "latest" back to the previous release while the exact-version entry stayed correct — so every pinned consumer, mcpp's own CI included, remained green, and only a version-less `xlings install mcpp` served the stale binary. Landing first also left the generated PR conflicting. Separately, the bootstrap pin reached main 19 seconds before the index PR merged. The nine workflows it triggered resolved the index 51 seconds after the new pointer asset had been replaced and still received the previous artifact; all nine failed at bootstrap without compiling a line. "Merged into xim-pkgindex" is therefore necessary but not sufficient — clients read a CDN artifact, not the git tree. Both criteria added here are stated as what resolves, not as the presence of a version string, and both were run verbatim against the repaired index. --- .agents/skills/mcpp-release/SKILL.md | 31 ++++++++++++++++++ docs/09-release.md | 48 ++++++++++++++++++++++++++++ docs/zh/09-release.md | 38 ++++++++++++++++++++++ 3 files changed, 117 insertions(+) diff --git a/.agents/skills/mcpp-release/SKILL.md b/.agents/skills/mcpp-release/SKILL.md index 3140d7be..72b406b7 100644 --- a/.agents/skills/mcpp-release/SKILL.md +++ b/.agents/skills/mcpp-release/SKILL.md @@ -228,10 +228,39 @@ git commit -am "ci: workspace mcpp bootstrap pin -> $NEW_VERSION (released, mirr **顺序不能反**:pin 一旦领先于"索引里真实存在的版本",每个 CI job 的 bootstrap 都会 `package 'mcpp@X.Y.Z' not found`。这就是 bump PR 里不许碰这两处的原因。 +**索引 PR 不要手写**:`publish-ecosystem` 已经开好了 bot PR —— 分支 +`bump/mcpp-`,提交者 `xlings-ci `,diff 恒为 **+22/-3**。 +承重的是那三行删除:生成器对每个平台表**替换** `["latest"]` 那一行,而不是新增一行。 +收尾时只要合入它。 + +2026-09-05 手写了一个平行的索引 PR(`xim-pkgindex#764`,分支 `feat/mcpp-`, ++22/**-0**),两个缺陷一起产生: + +- 追加而非替换,于是每个平台表里有两个 `["latest"]` 键。Lua 表构造器以最后一次赋值 + 为准,`latest` 静默解析回上一个发布。精确版本条目仍在且正确,**所以 mcpp 自己的 + CI(精确 pin)完全看不见**;只有不带版本的 `xlings install mcpp` 会拿到旧二进制。 +- 它先落地,bot 那份正确的 PR 变成冲突。解冲突时取 **bot 分支**那一侧的 + `pkgs/m/mcpp.lua` —— 它与手写后的 main 只差那几行陈旧的 `["latest"]`。 + **索引传播有滞后**:索引 artifact 发布后,`latest` tag 上的指针文件在 GitHub 资产 CDN 上可能还要几分钟才更新。紧接着跑的 CI 可能仍拿到旧索引并报 `package 'mcpp@X.Y.Z' not found` —— 这不是 release 坏了,等指针稳定后重跑即可。 +两个判据(都不是"文件里有这个版本字符串"): + +```bash +# 1) 索引 main 上,latest 解析到新版本:恰好三行,每平台一行,都指向新版本 +curl -fsSL https://raw.githubusercontent.com/openxlings/xim-pkgindex/main/pkgs/m/mcpp.lua \ + | grep -n '\["latest"\]' + +# 2) 推 pin 之前,指针已经跟上索引 main 的短 SHA +curl -fsSL https://github.com/xlings-res/xim-index/releases/download/latest/xim-index-latest.json \ + | grep -E '"(index_version|source_commit)"' +``` + +滞后的量级实测过:2026-09-05 那次,指针资产 17:20:32 就替换完了,CI 17:21:23 才去解析 +(晚 51 秒),拿到的仍是上一份 artifact。所以"索引 PR 合入了"不足以放行 pin,要看指针。 + ### 下游分发渠道(都是自动的,只需核验) 两条渠道都挂在 `release` workflow 的 `workflow_run: completed` 上,不需要人工推: @@ -256,6 +285,8 @@ gh workflow run bump-formula.yml -R mcpp-community/homebrew-mcpp |------|------|------| | `mcpp X.Y.Z-1` 但 tag 是 `vX.Y.Z` | `fingerprint.cppm` 版本未更新 | 更新 `MCPP_VERSION`,重新打 tag | | bump PR 里**所有** CI job 都红在 bootstrap,报 `package 'mcpp@X.Y.Z' not found` | 把 `.xlings.json` bootstrap pin 一起 bump 了,CI 去装一个还没发布的版本 | 把 `.xlings.json` 回退到上一个已发布版本;不要修改运行时推导的 `MCPP_PIN` | +| main 上**所有** workflow 都红在 bootstrap,报 `package 'mcpp@X.Y.Z' not found`,而该版本确实已发布并已合入索引 | pin 推得比索引指针稳定早;客户端读 CDN artifact 不读 git 树 | 等 `xim-index-latest.json` 的 `index_version` 等于索引 main 短 SHA 后重跑;不要改 pin | +| `xlings install mcpp`(不带 `@版本`)装到**上一个**版本,而索引文件里明明有新版本 | 同一平台表里两个 `["latest"]` 键(手写索引 PR 追加而非替换),Lua 后写的赢 | 删掉陈旧的那行,使每个平台表只剩一个 `["latest"]`。**精确 pin 仍可用,所以 mcpp 自己的 CI 不会报这个** | | 自查 `--version` 显示旧版本,但源码已改 | `target//<指纹>/` 的指纹随版本变,`ls \| head -1` 取到了上一次构建的目录 | 用 `ls -dt … \| head -1` 取最新构建 | | Smoke test 输出旧版本 | CI 缓存了旧的 sandbox/target | 删除 GitHub Actions cache 后重跑 | | e2e `01_help_and_version.sh` 挂 | 只改了 `mcpp.toml` 没改 `fingerprint.cppm`(它把两者交叉比对) | 同步两处正在构建的版本;注意这个 e2e 只在部分分片里跑,可能表现为"只有某个平台红" | diff --git a/docs/09-release.md b/docs/09-release.md index 144aeaf0..29871f24 100644 --- a/docs/09-release.md +++ b/docs/09-release.md @@ -89,6 +89,36 @@ Two steps are **not** automated: the released version is downloadable but not installable via `xlings install`. - **bumping `.xlings.json`** — see §4. +The bump PR is machine-authored: branch `bump/mcpp-`, commits by +`xlings-ci `, and a diff that is invariably +22/-3. The three +deletions are the load-bearing part — the generator *replaces* each platform +table's `["latest"]` line rather than adding one. A hand-written index PR is not +an equivalent shortcut, and filing one alongside the bot's carries two distinct +costs, both incurred on 2026-09-05 by `xim-pkgindex#764`: + +- The hand-written diff appended `["latest"] = { ref = "" }` above the + existing line instead of replacing it, leaving two `["latest"]` keys in every + platform table. A Lua table constructor takes the last assignment, so `latest` + resolved back to the previous release. The exact-version entry was present and + correct, so every pinned consumer stayed green — mcpp's own CI pins exactly and + never saw it. Only `xlings install mcpp` without a version served the stale + binary. +- Landing ahead of the bot's PR left that PR conflicting. The resolution is to + take the bot branch's side of `pkgs/m/mcpp.lua`; it differs from the + hand-written `main` only by the stale `["latest"]` lines. + +A merged bump PR is therefore confirmed by what `latest` resolves to, which the +presence of the version string elsewhere in the file does not answer: + +```bash +curl -fsSL https://raw.githubusercontent.com/openxlings/xim-pkgindex/main/pkgs/m/mcpp.lua \ + | grep -n '\["latest"\]' +``` + +Exactly three lines come back, one per platform table, and each names the version +just released. A fourth line, or one naming the previous release, is the +duplicate-key defect above. + ## 3. Verifying a release The mirror script verifies its own uploads, but the checks worth doing by hand @@ -169,6 +199,22 @@ is not yet installable. Bump it only after the release is published, mirrored, `check_version_pins.sh` enforces the weaker "never newer than the version being built"; the index condition requires human judgement. +"Merged into xim-pkgindex" is necessary but not sufficient: clients read a CDN +artifact, not the git tree. On 2026-09-05 the pin commit reached `main` 19 +seconds before the index PR merged, and the CI jobs it triggered resolved the +index 51 seconds *after* the new pointer asset had been replaced — and still +received the previous artifact. All nine workflows failed at bootstrap, none of +them having compiled a line. The observable condition is the pointer itself: + +```bash +curl -fsSL https://github.com/xlings-res/xim-index/releases/download/latest/xim-index-latest.json \ + | grep -E '"(index_version|source_commit)"' +``` + +`index_version` must equal the short SHA of xim-pkgindex `main` before the pin is +pushed. Nothing enforces this, and in the job log the resulting failure is +indistinguishable from a genuinely wrong version name. + ## 5. `MCPP_PIN` is derived, and why that matters `ci-fresh-install.yml` used to carry a second hand-edited copy of the pin. It was @@ -226,6 +272,8 @@ would again let the index guard and the installed version drift apart. [ ] downloaded mcpp-release.json regenerates byte-identically from public assets [ ] mirrors serve all four platforms on BOTH hosts, sha256 recomputed [ ] merge the xim-pkgindex bump PR +[ ] index `latest` resolves to the new version in all three platform tables +[ ] xim-index-latest.json's `index_version` equals xim-pkgindex `main` [ ] clean-room XLINGS_HOME: xlings install mcpp@ succeeds [ ] (optional) bump .xlings.json — only now, never earlier ``` diff --git a/docs/zh/09-release.md b/docs/zh/09-release.md index 8dc89010..947f5976 100644 --- a/docs/zh/09-release.md +++ b/docs/zh/09-release.md @@ -81,6 +81,29 @@ workflow 随后会再次下载公开 release、重新生成 manifest,并要求 可以下载,但无法通过 `xlings install` 安装。 - **bump `.xlings.json`** —— 见 §4。 +bump PR 是机器生成的:分支 `bump/mcpp-`,提交者 `xlings-ci +`,diff 恒为 +22/-3。承重的是那三行删除 —— 生成器对每个平台表是 +**替换** `["latest"]` 那一行,而不是新增一行。手写一个索引 PR 并不是等价的捷径; +在 bot 的 PR 之外另开一个,代价有两份,2026-09-05 的 `xim-pkgindex#764` 两份都付了: + +- 手写的 diff 把 `["latest"] = { ref = "<新版>" }` **追加**在原有那行上面而不是替换 + 它,于是每个平台表里留下两个 `["latest"]` 键。Lua 的表构造器以最后一次赋值为准, + `latest` 因此解析回上一个发布。精确版本条目存在且正确,所以每个按精确版本 pin 的 + 消费者都是绿的 —— mcpp 自己的 CI 正是精确 pin,完全看不见这件事。只有不带版本的 + `xlings install mcpp` 会拿到过期的二进制。 +- 它先于 bot 的 PR 落地,使那个 PR 变成冲突。解法是取 bot 分支那一侧的 + `pkgs/m/mcpp.lua`;它与手写后的 `main` 只差那几行陈旧的 `["latest"]`。 + +因此,bump PR 合入的判据是 `latest` **解析成什么**,而不是文件里别处出现了版本字符串: + +```bash +curl -fsSL https://raw.githubusercontent.com/openxlings/xim-pkgindex/main/pkgs/m/mcpp.lua \ + | grep -n '\["latest"\]' +``` + +恰好回来三行,每个平台表一行,且都指向刚发布的版本。出现第四行,或某一行指向上一个 +发布,就是上述的重复键缺陷。 + ## 3. 验证一次发布 镜像脚本会自校验上传,但真正值得手工做的是那些**不信任边车文件**的检查: @@ -153,6 +176,19 @@ $(find "$XLINGS_HOME" -name mcpp -type f -path '*/bin/*' | head -1) --version `package 'mcpp@' not found` 失败。待其语法问题修复后, `check_version_pins.sh` 能卡住较弱的「不得新于正在构建的版本」;索引那个条件需要人工把关。 +「已合入 xim-pkgindex」是必要条件而非充分条件:客户端读的是 CDN 上的 artifact,不是 +git 树。2026-09-05 那次,pin 的 commit 比索引 PR 的合入早到 `main` 19 秒,而它触发的 +CI 作业在新指针资产被替换**之后** 51 秒才去解析索引 —— 拿到的仍然是上一份 artifact。 +九条 workflow 全部死在 bootstrap,没有一条编译过一行。可观测的条件是指针本身: + +```bash +curl -fsSL https://github.com/xlings-res/xim-index/releases/download/latest/xim-index-latest.json \ + | grep -E '"(index_version|source_commit)"' +``` + +推 pin 之前,`index_version` 必须等于 xim-pkgindex `main` 的短 SHA。没有任何东西强制 +这一点,而在作业日志里,由此产生的失败与「版本名真的写错了」无法区分。 + ## 5. `MCPP_PIN` 改为推导,以及这为什么重要 `ci-fresh-install.yml` 过去带着 pin 的第二份手工副本。它们从来就不是一回事: @@ -191,6 +227,8 @@ $(find "$XLINGS_HOME" -name mcpp -type f -path '*/bin/*' | head -1) --version [ ] 下载的 mcpp-release.json 能从公开资产逐字节重新生成 [ ] 双端都服务四个平台,sha256 重新算过 [ ] 合并 xim-pkgindex 的 bump PR +[ ] 索引的 `latest` 在三个平台表里都解析到新版本 +[ ] xim-index-latest.json 的 `index_version` 等于 xim-pkgindex `main` [ ] clean-room XLINGS_HOME:xlings install mcpp@ 成功 [ ] (可选)bump .xlings.json —— 只在此刻,绝不提前 ```