diff --git a/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.i18n.yaml b/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.i18n.yaml index 75d7f8b670..19c54de94b 100644 --- a/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.i18n.yaml +++ b/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.md -2026-08-08-native-windows-pull-request-ci.md: 4e2ea07e90656f212f0613ffa17184ff2c3c8c45 -2026-08-08-native-windows-pull-request-ci.zh.md: 306243af3f3e0b280dd25caa5c99df2176590f3b +2026-08-08-native-windows-pull-request-ci.md: a1f294b2b9e73a5d14a00780c7b0adfaf58e4702 +2026-08-08-native-windows-pull-request-ci.zh.md: 2c91c21118f5ebbd9f0e341f7d31ec71481db4dc diff --git a/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.md b/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.md index 4e2ea07e90..a1f294b2b9 100644 --- a/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.md +++ b/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.md @@ -10,7 +10,7 @@ The required pull-request Windows verdict needs a fast win32 toolchain signal wi ## Decision -The required `windows` job in [ci.yml](../../../../.github/workflows/ci.yml) remains `windows node 24 / wine blocking` on `ubuntu-latest`. It retains the checksum-verified Windows Node, Wine apt and pnpm caches, a hoisted install confined to a workspace snapshot, and the [shared Wine gate script](../../../../scripts/wine-windows-gates.sh) that run the workspace build and production site. The stable `windows` job id remains a dependency of `all checks passed`. The [archived Wine experiment](../../archived/process/2026-07-27-wine-windows-gates-experiment.md) preserves its measured trade-offs, while this note owns the current dual topology. +The required `windows` job in [ci.yml](../../../../.github/workflows/ci.yml) remains `windows node 24 / wine blocking` on `ubuntu-latest`. It retains the checksum-verified Windows Node, Wine apt and pnpm caches, a hoisted install confined to a workspace snapshot, and the [shared Wine gate script](../../../../scripts/wine-windows-gates.sh) that runs the workspace build and production site. Node distribution transfers use bounded retries so a stalled download fails or recovers before consuming the job timeout. The stable `windows` job id remains a dependency of `all checks passed`. The [archived Wine experiment](../../archived/process/2026-07-27-wine-windows-gates-experiment.md) preserves its measured trade-offs, while this note owns the current dual topology. Every pull request also starts an independent `windows-native` job named `windows node 24 / native complete` on GitHub's standard `windows-2025` image. It enables Developer Mode for workspace symlinks, provisions the repository-pinned pnpm through `pnpm/action-setup`, performs an immutable install without a transferred store archive, and runs `pnpm run check:ci:windows-complete` under native PowerShell. The job is deliberately absent from `all-checks-passed.needs`: the aggregate neither waits for it nor changes conclusion because of it, while the native job retains its own unmasked success or failure result. diff --git a/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.zh.md b/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.zh.md index 306243af3f..2c91c21118 100644 --- a/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.zh.md +++ b/.agents/notes/implemented/process/2026-08-08-native-windows-pull-request-ci.zh.md @@ -10,7 +10,7 @@ Status: implemented ## 决策 -[ci.yml](../../../../.github/workflows/ci.yml) 中必需的 `windows` 作业仍是在 `ubuntu-latest` 上运行的 `windows node 24 / wine blocking`。它保留经过校验和验证的 Windows Node、Wine apt 与 pnpm 缓存、仅限工作区快照的 hoisted 安装,以及运行工作区构建与生产网站的[共享 Wine 门禁脚本](../../../../scripts/wine-windows-gates.sh)。稳定的 `windows` 作业 ID 仍是 `all checks passed` 的依赖项。[已归档的 Wine 实验](../../archived/process/2026-07-27-wine-windows-gates-experiment.md)保留其实测取舍,而本文负责当前双通道拓扑。 +[ci.yml](../../../../.github/workflows/ci.yml) 中必需的 `windows` 作业仍是在 `ubuntu-latest` 上运行的 `windows node 24 / wine blocking`。它保留经过校验和验证的 Windows Node、Wine apt 与 pnpm 缓存、仅限工作区快照的 hoisted 安装,以及运行工作区构建与生产网站的[共享 Wine 门禁脚本](../../../../scripts/wine-windows-gates.sh)。Node 分发文件传输采用有界重试,使停滞的下载在耗尽作业超时前失败或恢复。稳定的 `windows` 作业 ID 仍是 `all checks passed` 的依赖项。[已归档的 Wine 实验](../../archived/process/2026-07-27-wine-windows-gates-experiment.md)保留其实测取舍,而本文负责当前双通道拓扑。 每个拉取请求还会在 GitHub 标准 `windows-2025` 镜像上启动一个独立的 `windows-native` 作业,名称为 `windows node 24 / native complete`。该作业为工作区符号链接启用开发人员模式,通过 `pnpm/action-setup` 提供仓库固定版本的 pnpm,在不传输 store 归档的情况下执行不可变安装,并在原生 PowerShell 下运行 `pnpm run check:ci:windows-complete`。该作业被刻意排除在 `all-checks-passed.needs` 之外:聚合流程既不等待它,也不会因它改变结论;原生作业则保留自身未被掩盖的成功或失败结果。 diff --git a/scripts/wine-windows-gates.sh b/scripts/wine-windows-gates.sh index 9bf904a767..d4798fdd7b 100755 --- a/scripts/wine-windows-gates.sh +++ b/scripts/wine-windows-gates.sh @@ -74,19 +74,27 @@ trap cleanup EXIT mkdir -p "$cache_dir" "$scratch/logs" # ---- provision Windows Node, boot Wine, snapshot + install concurrently ---- +curl_download_args=( + --fail --silent --show-error --location + --retry 3 --retry-all-errors --retry-delay 2 + --connect-timeout 10 --max-time 90 --retry-max-time 240 +) + provision_node() { # Latest release of the primary line, checksum-verified against the same - # dist directory. Offline runs fall back to the newest cached zip, loudly. + # dist directory. Bound and retry every transfer so a stalled nodejs.org + # response cannot consume the entire CI job. Offline runs fall back to the + # newest cached zip, loudly. local version zip - version="$(curl -fsSL --max-time 30 https://nodejs.org/dist/index.json 2> /dev/null \ + version="$(curl "${curl_download_args[@]}" https://nodejs.org/dist/index.json 2> /dev/null \ | node -e "let d='';process.stdin.on('data',c=>d+=c).on('end',()=>{const v=JSON.parse(d).find(r=>r.version.startsWith('v$node_major.'));if(v)console.log(v.version)})" \ || true)" if [ -n "$version" ]; then zip="$cache_dir/node-$version-win-x64.zip" if [ ! -f "$zip" ]; then - curl -fsSL -o "$zip.tmp" "https://nodejs.org/dist/$version/node-$version-win-x64.zip" + curl "${curl_download_args[@]}" -o "$zip.tmp" "https://nodejs.org/dist/$version/node-$version-win-x64.zip" local expected - expected="$(curl -fsSL "https://nodejs.org/dist/$version/SHASUMS256.txt" \ + expected="$(curl "${curl_download_args[@]}" "https://nodejs.org/dist/$version/SHASUMS256.txt" \ | awk -v a="node-$version-win-x64.zip" '$2 == a { print $1; exit }')" [ -n "$expected" ] || { echo "wine-windows-gates: no SHASUMS256 entry for node-$version-win-x64.zip" >&2; exit 1; } verify_sha256 "$expected" "$zip.tmp"