From d766fdac562dd21990b4af1b68124c7cd1eb0917 Mon Sep 17 00:00:00 2001 From: elkaix Date: Sat, 22 Aug 2026 20:20:42 -0400 Subject: [PATCH 1/2] fix(ci): give the web build a heap ceiling and repair stale typecheck filters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `apps/pythinker-web` vite build needs just over 2 GB of old space since the workspace file editor pulled Monaco into the production graph. macOS runners default to a ~2053 MB ceiling, so three jobs died with exit 134: Desktop Release's `mac` and Release's `darwin-x64` / `darwin-arm64` native bundles. Linux and Windows runners default higher and stayed green, which is why CI never caught it. Setting the ceiling in the package's own build script covers every consumer — CI, Nix, both release workflows and local builds — and stays portable, unlike a `NODE_OPTIONS=` prefix, which cmd.exe rejects on the Windows desktop job. Measured floor: 2048 MB fails, 2560 MB passes; the build peaks near 2.2 GB. Separately, `pnpm --filter ` exits 0 when nothing matches, so three typecheck gates had gone quietly dead: `@pymodel/dashboard-server` and `@pymodel/dashboard-web` matched nothing after the vis rename, and `pythinker-code` matched the CLI directory instead of the VS Code extension (`pythinker`), leaving the extension unchecked. Resolving each filter before running it turns a stale name back into a failure. --- .github/workflows/ci.yml | 28 ++++++++++++------- .../dist-web/.web-bundle-manifest.json | 2 +- apps/pythinker-web/package.json | 2 +- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 847e12de6..f0e1b71bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -136,13 +136,21 @@ jobs: echo "Typechecking ${config}" pnpm dlx --package @typescript/native-preview@beta tsgo -p "${config}" --noEmit done - - name: Typecheck VS Code extension - run: pnpm --filter pythinker-code run typecheck - - name: Typecheck pythinker-web (vue-tsc) - run: pnpm --filter @pymodel/pythinker-web run typecheck - - name: Typecheck dashboard-server - run: pnpm --filter @pymodel/dashboard-server run typecheck - - name: Typecheck dashboard-web - run: pnpm --filter @pymodel/dashboard-web run typecheck - - name: Typecheck desktop - run: pnpm --filter @pymodel/pythinker-desktop run typecheck + # `pnpm --filter ` exits 0 when nothing matches, so a renamed + # package silently turns its gate into a no-op. Three of these filters + # had already gone stale that way: `@pymodel/dashboard-server` and + # `@pymodel/dashboard-web` matched nothing after the vis rename, and + # `pythinker-code` matched the CLI directory instead of the VS Code + # extension (`pythinker`), so the extension was never typechecked here. + # Resolving each filter first turns a stale name back into a failure. + - name: Typecheck workspace apps + run: | + set -euo pipefail + for package in pythinker @pymodel/pythinker-web @pymodel/vis-server @pymodel/vis-web @pymodel/pythinker-desktop; do + if [ -z "$(pnpm ls --filter "$package" --depth -1 --parseable)" ]; then + echo "No workspace package matches the filter '${package}'" >&2 + exit 1 + fi + echo "Typechecking ${package}" + pnpm --filter "$package" run typecheck + done diff --git a/apps/pythinker-code/dist-web/.web-bundle-manifest.json b/apps/pythinker-code/dist-web/.web-bundle-manifest.json index 64c981108..c2823588f 100644 --- a/apps/pythinker-code/dist-web/.web-bundle-manifest.json +++ b/apps/pythinker-code/dist-web/.web-bundle-manifest.json @@ -1,4 +1,4 @@ { - "sourceHash": "dcb2227d96cf476915942656bc127bb1d7801258b01daa6995ee76e915ff199b", + "sourceHash": "39adcc1ccb551ac03f06fe2152c6a69004701da14fd2535f8b26202cb9d27c14", "sourceFileCount": 389 } diff --git a/apps/pythinker-web/package.json b/apps/pythinker-web/package.json index fa9ca06b5..96f5b74bd 100644 --- a/apps/pythinker-web/package.json +++ b/apps/pythinker-web/package.json @@ -6,7 +6,7 @@ "type": "module", "scripts": { "dev": "vite", - "build": "vite build", + "build": "node --max-old-space-size=4096 ./node_modules/vite/bin/vite.js build", "typecheck": "vue-tsc --noEmit", "test": "vitest run", "check:style": "node scripts/check-style.mjs", From 2559b1cde1d2bc4903df8d58f0bd6ee1a61e83d5 Mon Sep 17 00:00:00 2001 From: elkaix Date: Sat, 22 Aug 2026 20:28:23 -0400 Subject: [PATCH 2/2] fix(ci): stop a half-shipped release from passing as a good one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `publish-native-assets` correctly refuses to publish a partial native set, but a job whose dependency failed reports `skipped`, not `failure`. `redeploy-cdn` only checked for `failure`, so it deployed 1.0.0 to the CDN while the GitHub release held zero assets — every native installer would have been pointed at a release that has none. It now requires that job to have succeeded whenever the release has native artifacts at all, leaving the CDN on the last installable version otherwise. `verify-cdn-release` had no `always()`, so the same upstream skip propagated through the graph and silently disabled the one gate that exists to catch a half-shipped release. It now runs on its own merits and reports the stale CDN instead of vanishing with it. --- .github/workflows/release.yml | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cf9f2dc83..4cd4a02c6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -240,11 +240,18 @@ jobs: needs: - release - publish-native-assets + # A native release whose zips never reached the GitHub release must not + # reach the CDN either. `publish-native-assets` refuses to publish a + # partial set, and a job whose needs failed reports `skipped`, not + # `failure` — so checking only for failure let a release with zero assets + # through and pointed every native installer at a release that has none. + # Requiring success (only when this release has native artifacts at all) + # leaves the CDN on the last installable version instead. if: >- always() && needs.release.result == 'success' - && needs.publish-native-assets.result != 'failure' - && needs.publish-native-assets.result != 'cancelled' + && (needs.release.outputs.pythinker_native_release != 'true' + || needs.publish-native-assets.result == 'success') && (needs.release.outputs.packages_published == 'true' || startsWith(github.event.head_commit.message, 'ci: release packages')) runs-on: ubuntu-latest @@ -308,9 +315,16 @@ jobs: needs: - release - redeploy-cdn + # Without `always()` a skip anywhere upstream skips this job too, and the + # gate that exists to catch a half-shipped release goes quiet in exactly + # the runs that need it. It stays out of `redeploy-cdn`'s result on + # purpose: a CDN that never redeployed is the failure this asserts, so it + # has to run and report it rather than disappear with it. if: >- - needs.release.outputs.packages_published == 'true' - || startsWith(github.event.head_commit.message, 'ci: release packages') + always() + && needs.release.result == 'success' + && (needs.release.outputs.packages_published == 'true' + || startsWith(github.event.head_commit.message, 'ci: release packages')) runs-on: ubuntu-latest steps: - name: Checkout