From e0fd4c961c5b281d41ca6679a4de94bb3bf36952 Mon Sep 17 00:00:00 2001 From: jdalton Date: Mon, 5 Oct 2026 14:44:39 -0400 Subject: [PATCH 1/3] build: add dev and production profiles with faster CI lanes --- .github/workflows/auto-opt-app-patterns.yml | 2 +- .github/workflows/benchmark.yml | 6 +- .github/workflows/container-tests.yml | 8 +- .github/workflows/coverage.yml | 2 +- .github/workflows/eh-transport.yml | 2 +- .github/workflows/ext-link.yml | 2 +- .github/workflows/feature-matrix.yml | 2 +- .github/workflows/gc-moving-witnesses.yml | 2 +- .github/workflows/gc-native-roots.yml | 2 +- .github/workflows/gc-parse-churn-gate.yml | 2 +- .../workflows/gc-ptr-shape-off-witness.yml | 2 +- .github/workflows/gc-ratchet.yml | 2 +- .github/workflows/gc-root-dominance.yml | 4 +- .github/workflows/next-app-route.yml | 2 +- .github/workflows/node-compat-matrix.yml | 2 +- .github/workflows/node-core-subset.yml | 2 +- .github/workflows/node-suite-guard.yml | 2 +- .github/workflows/npm-package-sweep.yml | 2 +- .github/workflows/release-packages.yml | 92 +- .github/workflows/security-audit.yml | 4 +- .github/workflows/simctl-tests.yml | 2 +- .github/workflows/test.yml | 135 +- .github/workflows/tls-budget.yml | 2 +- .github/workflows/wasi-check.yml | 4 +- CLAUDE.md | 10 +- CONTRIBUTING.md | 9 +- Cargo.toml | 60 +- Makefile | 27 +- crates/perry/src/panic_profile_contract.rs | 25 +- ...unction_apply_dynamic_args_eval_surface.rs | 6 +- docs/src/contributing/building.md | 53 +- docs/src/testing/ci-tiers.md | 34 +- external-tools.json | 25 +- package-lock.json | 1396 ++++++++++++++++- package.json | 1 + rust-toolchain.toml | 10 +- scripts/build_core_runtime.sh | 19 +- scripts/build_linux_glibc_2_31.sh | 24 +- scripts/build_linux_musl.sh | 22 +- scripts/cargo_timing_summary.py | 2 +- scripts/check_gc_header_constants.py | 2 +- scripts/ci_plan.py | 4 +- scripts/node_compat_matrix.mjs | 11 +- scripts/publish/brew/formula.mts | 8 +- scripts/run_windows_runtime_regressions.py | 4 +- scripts/test-async-resource-own-bind.mjs | 2 +- scripts/test-bun-embedded-compression.mjs | 2 +- scripts/test-bun-text-modules.mjs | 2 +- scripts/test-child-output-late-iterator.mjs | 2 +- ...est-export-dollar-underscore-collision.mjs | 2 +- scripts/test-exported-local-storage.mjs | 2 +- scripts/test-import-meta-require-value.mjs | 2 +- .../test-imported-value-class-collision.mjs | 2 +- scripts/test-loop-lexical-tdz.mjs | 2 +- scripts/test-minsize-inline-policy.mjs | 2 +- ...test-namespace-getter-binding-identity.mjs | 2 +- scripts/test-object-array-methods.mjs | 2 +- scripts/test-require-runtime.mjs | 10 +- scripts/test-require-runtime.test.mjs | 2 +- scripts/test-string-static-spread.mjs | 2 +- 60 files changed, 1799 insertions(+), 278 deletions(-) diff --git a/.github/workflows/auto-opt-app-patterns.yml b/.github/workflows/auto-opt-app-patterns.yml index 832776a036..7b4737084a 100644 --- a/.github/workflows/auto-opt-app-patterns.yml +++ b/.github/workflows/auto-opt-app-patterns.yml @@ -155,7 +155,7 @@ jobs: - name: Install Rust toolchain if: steps.relevance.outputs.run == 'true' - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 9735b260cd..56a1074344 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -64,7 +64,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Cache cargo @@ -306,7 +306,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Cache cargo @@ -424,7 +424,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Measure clean-build time diff --git a/.github/workflows/container-tests.yml b/.github/workflows/container-tests.yml index 56601ee59f..ad211a53b5 100644 --- a/.github/workflows/container-tests.yml +++ b/.github/workflows/container-tests.yml @@ -116,7 +116,7 @@ jobs: df -h / | tail -1 - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Cache cargo registry @@ -210,7 +210,7 @@ jobs: df -h / | tail -1 - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Cache cargo registry @@ -272,7 +272,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Cache cargo registry @@ -336,7 +336,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Cache cargo registry diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index aeca797f7d..0d9406ed59 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -55,7 +55,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal --component llvm-tools-preview + run: rustup toolchain install nightly-2026-10-04 --profile minimal --component llvm-tools-preview - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 diff --git a/.github/workflows/eh-transport.yml b/.github/workflows/eh-transport.yml index 913e9037d8..d4c652c4fe 100644 --- a/.github/workflows/eh-transport.yml +++ b/.github/workflows/eh-transport.yml @@ -135,7 +135,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Setup Node.js diff --git a/.github/workflows/ext-link.yml b/.github/workflows/ext-link.yml index 9b36d0ab9f..5e104c910c 100644 --- a/.github/workflows/ext-link.yml +++ b/.github/workflows/ext-link.yml @@ -129,7 +129,7 @@ jobs: - name: Install Rust toolchain if: steps.scope.outputs.pkgs != '' - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - if: steps.scope.outputs.pkgs != '' uses: ./.github/actions/setup-llvm22 diff --git a/.github/workflows/feature-matrix.yml b/.github/workflows/feature-matrix.yml index 3618e03a69..94821bd983 100644 --- a/.github/workflows/feature-matrix.yml +++ b/.github/workflows/feature-matrix.yml @@ -58,7 +58,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 diff --git a/.github/workflows/gc-moving-witnesses.yml b/.github/workflows/gc-moving-witnesses.yml index c1e14cf9c2..125ce600a7 100644 --- a/.github/workflows/gc-moving-witnesses.yml +++ b/.github/workflows/gc-moving-witnesses.yml @@ -242,7 +242,7 @@ jobs: - name: Install Rust toolchain if: steps.relevance.outputs.run == 'true' - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 diff --git a/.github/workflows/gc-native-roots.yml b/.github/workflows/gc-native-roots.yml index 88924e8585..f560601c4f 100644 --- a/.github/workflows/gc-native-roots.yml +++ b/.github/workflows/gc-native-roots.yml @@ -299,7 +299,7 @@ jobs: with: node-version-file: .node-version - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 with: diff --git a/.github/workflows/gc-parse-churn-gate.yml b/.github/workflows/gc-parse-churn-gate.yml index f352903cd0..e97f91cadb 100644 --- a/.github/workflows/gc-parse-churn-gate.yml +++ b/.github/workflows/gc-parse-churn-gate.yml @@ -218,7 +218,7 @@ jobs: - name: Install Rust toolchain if: steps.relevance.outputs.run == 'true' - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 if: steps.relevance.outputs.run == 'true' diff --git a/.github/workflows/gc-ptr-shape-off-witness.yml b/.github/workflows/gc-ptr-shape-off-witness.yml index 0903a30a59..0902436380 100644 --- a/.github/workflows/gc-ptr-shape-off-witness.yml +++ b/.github/workflows/gc-ptr-shape-off-witness.yml @@ -186,7 +186,7 @@ jobs: - name: Install Rust toolchain if: steps.relevance.outputs.run == 'true' - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 if: steps.relevance.outputs.run == 'true' diff --git a/.github/workflows/gc-ratchet.yml b/.github/workflows/gc-ratchet.yml index 52dd1f66f9..19c49f5743 100644 --- a/.github/workflows/gc-ratchet.yml +++ b/.github/workflows/gc-ratchet.yml @@ -177,7 +177,7 @@ jobs: - name: Install Rust toolchain if: steps.relevance.outputs.run == 'true' - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Cache cargo diff --git a/.github/workflows/gc-root-dominance.yml b/.github/workflows/gc-root-dominance.yml index 6f43ccdb69..c9ba11ab26 100644 --- a/.github/workflows/gc-root-dominance.yml +++ b/.github/workflows/gc-root-dominance.yml @@ -230,7 +230,7 @@ jobs: run: python3 scripts/gc_root_dominance_check.py --audit-immovable-sources - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 # ★ The dependency-scale corpus needs the dependency. @@ -562,7 +562,7 @@ jobs: run: npm ci --ignore-scripts --no-audit --no-fund - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal # This also puts a matched LLVM 22 `opt` on disk and exports # LLVM_SYS_221_PREFIX, which is how the corpus script finds it. The # native corpus is `--trace llvm` output PLUS the production statepoint diff --git a/.github/workflows/next-app-route.yml b/.github/workflows/next-app-route.yml index 052e78219a..0b70d19f20 100644 --- a/.github/workflows/next-app-route.yml +++ b/.github/workflows/next-app-route.yml @@ -58,7 +58,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/mozilla-actions/sccache-action # v0.0.11 diff --git a/.github/workflows/node-compat-matrix.yml b/.github/workflows/node-compat-matrix.yml index 365c328192..d88b6091a0 100644 --- a/.github/workflows/node-compat-matrix.yml +++ b/.github/workflows/node-compat-matrix.yml @@ -77,7 +77,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Start sccache diff --git a/.github/workflows/node-core-subset.yml b/.github/workflows/node-core-subset.yml index d4a517e6e5..4af8936f82 100644 --- a/.github/workflows/node-core-subset.yml +++ b/.github/workflows/node-core-subset.yml @@ -93,7 +93,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 diff --git a/.github/workflows/node-suite-guard.yml b/.github/workflows/node-suite-guard.yml index e8fa68a898..fe480e1615 100644 --- a/.github/workflows/node-suite-guard.yml +++ b/.github/workflows/node-suite-guard.yml @@ -65,7 +65,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Start sccache diff --git a/.github/workflows/npm-package-sweep.yml b/.github/workflows/npm-package-sweep.yml index 4aa27c768b..813da3d485 100644 --- a/.github/workflows/npm-package-sweep.yml +++ b/.github/workflows/npm-package-sweep.yml @@ -64,7 +64,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 diff --git a/.github/workflows/release-packages.yml b/.github/workflows/release-packages.yml index c51fbbf48c..6b6a65e2bd 100644 --- a/.github/workflows/release-packages.yml +++ b/.github/workflows/release-packages.yml @@ -508,12 +508,8 @@ jobs: # `rust-cache` saved nothing, leaving that leg unable to warm its own cache: # it cannot finish without a cache and cannot cache without finishing. # - # This job breaks the loop. `rust-cache` caches THIRD-PARTY dependencies only - # (it deliberately evicts workspace-crate fingerprints -- see #4856 in the - # build job), and those are the bulk of a cold build. Compiling them here - # under a timeout safely inside the ceiling, with `cache-on-failure`, saves - # the cache even if this job does not finish, so `build` starts from - # compiled dependencies. + # This job breaks the loop. Compile with mbx and save completed + # content-addressed objects so `build` can reuse dependency work. # # `continue-on-error` is deliberate: this is an optimization, never a gate. # If it fails or times out, `build` runs exactly as it would have. @@ -546,7 +542,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal --target x86_64-apple-darwin + run: rustup toolchain install nightly-2026-10-04 --profile minimal --target x86_64-apple-darwin - uses: ./.github/actions/setup-llvm22 # Keep the proven partial-failure cache for this exceptionally slow # Intel leg. mbx's object bundle is saved only after a successful job. @@ -559,7 +555,7 @@ jobs: workspaces: | . -> target - name: Compile dependencies for x86_64-apple-darwin - run: cargo build --profile dist --target x86_64-apple-darwin -p perry + run: mbx build --profile prod --target x86_64-apple-darwin -p perry # --------------------------------------------------------------------------- # Build release binaries for all platforms @@ -674,7 +670,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal --target ${{ matrix.target }} + run: rustup toolchain install nightly-2026-10-04 --profile minimal --target ${{ matrix.target }} # The old-sysroot image carries LLVM 22 under /usr/lib/llvm-22. # Its host-side GTK4 build does not depend on perry-codegen, so avoid # installing a second LLVM copy on the noble runner for these two legs. @@ -707,16 +703,16 @@ jobs: run: | set -euo pipefail while IFS= read -r pkg; do - rm -rf target/dist/.fingerprint/"$pkg"-* \ - target/*/dist/.fingerprint/"$pkg"-* \ - target-glibc231/dist/.fingerprint/"$pkg"-* \ - target-glibc231/*/dist/.fingerprint/"$pkg"-* \ - target-glibc231-abort/dist/.fingerprint/"$pkg"-* \ - target-glibc231-abort/*/dist/.fingerprint/"$pkg"-* \ - target-musl/dist/.fingerprint/"$pkg"-* \ - target-musl/*/dist/.fingerprint/"$pkg"-* \ - target-musl-abort/dist/.fingerprint/"$pkg"-* \ - target-musl-abort/*/dist/.fingerprint/"$pkg"-* + rm -rf target/prod/.fingerprint/"$pkg"-* \ + target/*/prod/.fingerprint/"$pkg"-* \ + target-glibc231/prod/.fingerprint/"$pkg"-* \ + target-glibc231/*/prod/.fingerprint/"$pkg"-* \ + target-glibc231-abort/prod/.fingerprint/"$pkg"-* \ + target-glibc231-abort/*/prod/.fingerprint/"$pkg"-* \ + target-musl/prod/.fingerprint/"$pkg"-* \ + target-musl/*/prod/.fingerprint/"$pkg"-* \ + target-musl-abort/prod/.fingerprint/"$pkg"-* \ + target-musl-abort/*/prod/.fingerprint/"$pkg"-* done < <(cargo metadata --no-deps --format-version 1 | jq -r '.packages[].name') # Closes #394: Homebrew bottle was missing libperry_ui_ios.a so @@ -781,13 +777,13 @@ jobs: # crate, which downloaded a prebuilt V8 that 404'd on musl, was # removed.) if: matrix.old_glibc_image == '' && matrix.musl_image == '' - run: cargo build --profile dist --target ${{ matrix.target }} -p perry + run: mbx build --profile prod --target ${{ matrix.target }} -p perry - name: Build runtime libraries if: matrix.old_glibc_image == '' && matrix.musl_image == '' run: | - cargo build --profile dist --target ${{ matrix.target }} -p perry-runtime -p perry-runtime-static - cargo build --profile dist --target ${{ matrix.target }} -p perry-stdlib -p perry-stdlib-static + mbx build --profile prod --target ${{ matrix.target }} -p perry-runtime -p perry-runtime-static + mbx build --profile prod --target ${{ matrix.target }} -p perry-stdlib -p perry-stdlib-static - name: Build panic=abort runtime variant (Unix) # Out-of-tree installs can't rebuild the runtime, so ship the @@ -799,10 +795,10 @@ jobs: # invalidate the main build's incremental cache. if: runner.os != 'Windows' && matrix.old_glibc_image == '' && matrix.musl_image == '' run: | - CARGO_TARGET_DIR=target-abort CARGO_PROFILE_DIST_PANIC=abort \ - cargo build --profile dist --target ${{ matrix.target }} -p perry-runtime -p perry-runtime-static - cp "target-abort/${{ matrix.target }}/dist/libperry_runtime.a" \ - "target/${{ matrix.target }}/dist/libperry_runtime_abort.a" + CARGO_TARGET_DIR=target-abort CARGO_PROFILE_PROD_PANIC=abort \ + mbx build --profile prod --target ${{ matrix.target }} -p perry-runtime -p perry-runtime-static + cp "target-abort/${{ matrix.target }}/prod/libperry_runtime.a" \ + "target/${{ matrix.target }}/prod/libperry_runtime_abort.a" - name: Build core runtime profile (Unix) if: runner.os != 'Windows' && matrix.old_glibc_image == '' && matrix.musl_image == '' @@ -832,7 +828,7 @@ jobs: governed_ext_packages=$(./scripts/release_ext_packages.sh) while IFS= read -r name; do echo "::group::build $name" - cargo build --profile dist --target ${{ matrix.target }} \ + mbx build --profile prod --target ${{ matrix.target }} \ -p perry -p perry-runtime-static -p perry-stdlib-static -p "$name" \ || echo " (skipped $name — failed to build on this host)" echo "::endgroup::" @@ -931,7 +927,7 @@ jobs: - name: Build UI library (macOS) if: runner.os == 'macOS' - run: cargo build --profile dist --target ${{ matrix.target }} -p perry-ui-macos + run: mbx build --profile prod --target ${{ matrix.target }} -p perry-ui-macos # Closes #394: cross-compile the runtime + stdlib + UI for both the # iOS device and simulator triples (both Tier-2 stable). Library @@ -950,18 +946,18 @@ jobs: if: runner.os == 'macOS' && matrix.target == 'aarch64-apple-darwin' run: | for triple in aarch64-apple-ios aarch64-apple-ios-sim; do - cargo build --profile dist --target "$triple" -p perry-runtime -p perry-runtime-static - cargo build --profile dist --target "$triple" -p perry-stdlib -p perry-stdlib-static - cargo build --profile dist --target "$triple" -p perry-ui-ios + mbx build --profile prod --target "$triple" -p perry-runtime -p perry-runtime-static + mbx build --profile prod --target "$triple" -p perry-stdlib -p perry-stdlib-static + mbx build --profile prod --target "$triple" -p perry-ui-ios done - name: Build UI library (Linux glibc) if: runner.os == 'Linux' && !endsWith(matrix.target, '-musl') - run: cargo build --profile dist --target ${{ matrix.target }} -p perry-ui-gtk4 + run: mbx build --profile prod --target ${{ matrix.target }} -p perry-ui-gtk4 - name: Build UI library (Windows) if: runner.os == 'Windows' - run: cargo build --profile dist --target ${{ matrix.target }} -p perry-ui-windows + run: mbx build --profile prod --target ${{ matrix.target }} -p perry-ui-windows # Closes #872 / #4823: cross-compile the Android runtime libs (and the # perry-ui-android UI backend) on the Windows leg so the WinGet zip @@ -1023,19 +1019,19 @@ jobs: # pwsh has no `set -e`; these two are mandatory, so fail the step on a # non-zero exit (otherwise the best-effort UI build below, which resets # $LASTEXITCODE, could mask a runtime/stdlib failure). - cargo build --profile dist --target aarch64-linux-android -p perry-runtime -p perry-runtime-static + mbx build --profile prod --target aarch64-linux-android -p perry-runtime -p perry-runtime-static if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - cargo build --profile dist --target aarch64-linux-android -p perry-stdlib -p perry-stdlib-static + mbx build --profile prod --target aarch64-linux-android -p perry-stdlib -p perry-stdlib-static if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # #4823 (option 1): the Android UI backend so a WinGet/Scoop-installed # perry can link `perry/ui` apps for android without a source tree. # This is mandatory for every Windows archive: matrix legs package # independently, so another leg cannot backfill a missing library. - # Mirrors the ubuntu cross-bundle leg: `--profile dist` build for the + # Mirrors the ubuntu cross-bundle leg: `--profile prod` build for the # staticlib (UI crates are already staticlib — no -static wrapper); the # global-dynamic TLS rustflag only matters at the consumer's final # cdylib link, not here. - cargo build --profile dist --target aarch64-linux-android -p perry-ui-android + mbx build --profile prod --target aarch64-linux-android -p perry-ui-android if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # #4856 — defense in depth behind the cache eviction above: assert @@ -1474,7 +1470,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain + cross target - run: rustup toolchain install nightly-2026-08-20 --profile minimal --target ${{ matrix.target }} + run: rustup toolchain install nightly-2026-10-04 --profile minimal --target ${{ matrix.target }} - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 @@ -1494,8 +1490,8 @@ jobs: run: | set -euo pipefail while IFS= read -r pkg; do - rm -rf target/dist/.fingerprint/"$pkg"-* \ - target/*/dist/.fingerprint/"$pkg"-* + rm -rf target/prod/.fingerprint/"$pkg"-* \ + target/*/prod/.fingerprint/"$pkg"-* done < <(cargo metadata --no-deps --format-version 1 | jq -r '.packages[].name') # --- Per-runner toolchain wiring -------------------------------------- @@ -1558,12 +1554,12 @@ jobs: shell: bash run: | set -euo pipefail - cargo build --profile dist --target ${{ matrix.target }} -p perry-runtime -p perry-runtime-static - cargo build --profile dist --target ${{ matrix.target }} -p perry-stdlib -p perry-stdlib-static + mbx build --profile prod --target ${{ matrix.target }} -p perry-runtime -p perry-runtime-static + mbx build --profile prod --target ${{ matrix.target }} -p perry-stdlib -p perry-stdlib-static # UI crate is matrix-driven. perry-ui-android needs the NDK env # we wired above; perry-ui-windows builds against the MSVC SDK # already on windows-latest. Both go through plain `cargo build`. - cargo build --profile dist --target ${{ matrix.target }} -p ${{ matrix.ui_crate }} + mbx build --profile prod --target ${{ matrix.target }} -p ${{ matrix.ui_crate }} # #4856 — defense in depth behind the cache eviction above: a stale # cached runtime archive fails the release here instead of breaking @@ -1662,7 +1658,7 @@ jobs: # behavior at line ~448 above. $libs = @("perry_runtime.lib", "perry_stdlib.lib", $uiLib) foreach ($lib in $libs) { - $src = "target/$target/dist/$lib" + $src = "target/$target/prod/$lib" if (-not (Test-Path $src)) { Write-Error "Expected $src after build but it's missing — aborting bundle." exit 1 @@ -2063,10 +2059,10 @@ jobs: bin.install "perry" lib.install Dir["libperry_*.a"] else - system "cargo", "build", "--release" - system "cargo", "build", "--release", "-p", "perry-runtime", "-p", "perry-stdlib", "-p", "perry-runtime-static", "-p", "perry-stdlib-static" - bin.install "target/release/perry" - lib.install Dir["target/release/libperry_*.a"] + system "cargo", "build", "--profile", "prod" + system "cargo", "build", "--profile", "prod", "-p", "perry-runtime", "-p", "perry-stdlib", "-p", "perry-runtime-static", "-p", "perry-stdlib-static" + bin.install "target/prod/perry" + lib.install Dir["target/prod/libperry_*.a"] end end diff --git a/.github/workflows/security-audit.yml b/.github/workflows/security-audit.yml index 3e04d27626..e645f0c69c 100644 --- a/.github/workflows/security-audit.yml +++ b/.github/workflows/security-audit.yml @@ -68,7 +68,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 with: @@ -303,7 +303,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 with: diff --git a/.github/workflows/simctl-tests.yml b/.github/workflows/simctl-tests.yml index 670f4a4a25..ee77dd5735 100644 --- a/.github/workflows/simctl-tests.yml +++ b/.github/workflows/simctl-tests.yml @@ -52,7 +52,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Install iOS simulator Rust target diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b3321823fd..a7c11d6aed 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -263,7 +263,7 @@ jobs: run: ./tests/test_parity_compile_budget.sh - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal --component rustfmt --component clippy + run: rustup toolchain install nightly-2026-10-04 --profile minimal --component rustfmt --component clippy - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 @@ -823,7 +823,7 @@ jobs: # GC_FLAG_FORWARDED, GC_OBJ_TYPED_LAYOUT_INTACT and friends, held together # only by a comment -- the `debug_assert_eq!` that looks like it checks # them compares codegen's constant to a string literal (a tautology) and - # is compiled out of release and perry-dev anyway. A renumbering in the + # is compiled out of release, prod, and perry-dev anyway. A renumbering in the # runtime therefore compiled clean, passed every suite, and shipped a # binary whose objects the collector misreads. Build-free, so it belongs # in `lint`, which IS a required context. @@ -1127,7 +1127,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal --component clippy + run: rustup toolchain install nightly-2026-10-04 --profile minimal --component clippy - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 @@ -1245,7 +1245,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Install sccache @@ -1300,8 +1300,8 @@ jobs: # artifacts USED to live here. It only fed `binary-size` (which now does # its own quick build) — every other job did `cargo build --release` # itself anyway, so `needs: build` was a serializing barrier with no - # cache benefit. Removed in v0.5.387 along with the `actions/cache@v4` - # blocks (replaced by `Swatinem/rust-cache@v2`, which handles target/ + # cache benefit. Removed in v0.5.387 along with the `./.github/actions/perry/actions/cache@v4` + # blocks (replaced by `./.github/actions/perry/Swatinem/rust-cache@v2`, which handles target/ # pruning intelligently and avoids the disk-pressure issue that # required the manual simulator-runtime wipe + cache=registry-only # workaround). Each downstream job below builds in parallel directly. @@ -1316,17 +1316,12 @@ jobs: # don't exercise any platform behavior; they're pure logic + # codegen. runs-on: ubuntu-latest - # The per-package serial build+prune loop below (plus the big stdlib links) - # takes ~50-60 min with a WARM sccache disk cache. A fully cold cache - # (recompiling the whole dependency graph) measured ~90-103 min, and PRs - # that invalidate perry-runtime/perry-codegen previously exceeded the old - # 120-min bound entirely. The bound is 180 to (a) leave headroom while the - # disk cache warms after the sccache-backend fix, and (b) still cut a true - # hang (e.g. a flaky link SIGBUS retry storm). Once warm hit rates are - # confirmed in CI this can come back down. NOTE: the old "~45-50 min" figure - # predated the sccache GHA-backend rot — it was never accurate once that - # cache stopped delivering Rust hits. - timeout-minutes: 180 + # Use lane-sized job bounds: PR-scoped unit tests must fit the 30-minute + # required-gate budget; full workspace runs get 120 minutes. The latter + # leaves headroom above the measured 90-103-minute cold-cache baseline. + # Perry's large integration inventory is isolated in the eight-shard slow + # lane, with its own 120-minute cap per shard. + timeout-minutes: ${{ fromJSON(needs.plan.outputs.plan).cargo_test_scope == 'pr' && 30 || fromJSON(needs.plan.outputs.plan).tier == 'pr' && 180 || 120 }} # sccache (compiler-level cache, shared across ALL branches/jobs via the # GitHub Actions cache backend) on top of Swatinem/rust-cache (target/ + # registry). rust-cache only writes on main (save-if below), so PRs can't @@ -1377,7 +1372,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Install sccache @@ -1496,8 +1491,11 @@ jobs: # Run perry-runtime single-threaded so the tests can't interfere. if [ "${{ fromJSON(needs.plan.outputs.plan).cargo_test_scope }}" != "pr" ]; then - # ---- FULL run: release tags / nightly cron / workflow_dispatch ---- - # Every target, including the slow auto-optimize integration tests. + # ---- Full workspace run: main sweep / release / nightly ---- + # Main sweeps cover the full unit-test inventory and other package + # suites. Perry's large integration inventory is the slow lane: + # changed suites run in e2e-scoped on PRs, and the complete set + # runs in cargo-test-perry on the full tier. if printf '%s\n' "$scope" | grep -qx 'perry-runtime'; then RUST_TEST_THREADS=1 cargo test -p perry-runtime fi @@ -1509,7 +1507,7 @@ jobs: # directly and fail with "Could not find libperry_runtime.a" if the # cached staticlib was invalidated. Build them explicitly. # #8479: build these with `--release`. The `panic` strategy is a - # PROFILE-level setting, and only `release`/`dist`/`perry-dev` set + # PROFILE-level setting, and `dev`/`release`/`prod`/`dist`/`perry-dev` set # `panic = "abort"` — a bare `cargo build` produces a DEBUG, # `panic = "unwind"` runtime. Under `panic = "unwind"` rustc plants # an RFC-2945 abort guard in every `extern "C"` helper, which a JS @@ -1525,19 +1523,11 @@ jobs: # `function_apply_with_runtime_args_defers_to_a_located_aot_error` # pass. if printf '%s\n' "$scope" | grep -qE '^(perry|perry-stdlib)$'; then - if printf '%s\n' "$scope" | grep -qx 'perry' && [ "${{ needs.plan.outputs.tier }}" != "full" ]; then - # Sweep tier runs every perry integration target here, including - # the coherent-require fixtures. Prepare their providers in one - # graph outside the fixture's ten-minute spawnSync bound, else - # the fixture rebuilds the perry-dev graph and ETIMEDOUTs. - cargo build --release -p perry -p perry-runtime -p perry-stdlib \ - -p perry-runtime-static -p perry-stdlib-static \ - -p perry-ext-http -p perry-ext-net \ - -p perry-ext-typescript -p perry-ext-ws -p perry-ext-zlib - export PERRY_TEST_RUNTIME_PREBUILT=1 - else - cargo build --release -p perry-runtime -p perry-stdlib -p perry-runtime-static -p perry-stdlib-static - fi + # These runs need the shipped runtime archives. The slow perry + # integration fixtures prepare extra compiler/ext providers in + # their own full-tier shards. + cargo build --release -p perry-runtime -p perry-stdlib \ + -p perry-runtime-static -p perry-stdlib-static export PERRY_RUNTIME_DIR="$PWD/target/release" fi find target/debug/deps -maxdepth 1 -type f -perm -111 ! -name '*.so' -delete 2>/dev/null || true @@ -1546,10 +1536,9 @@ jobs: # disk doesn't exhaust mid-job. export CARGO_BUILD_JOBS=1 for package in $(printf '%s\n' "$scope" | grep -vx 'perry-runtime'); do - if [ "$package" = "perry" ] && [ "${{ needs.plan.outputs.tier }}" = "full" ]; then - # The full tier's cargo-test-perry matrix owns every perry - # integration target. Keep the bin/unit target here so the - # split is exhaustive without running any target twice. + if [ "$package" = "perry" ] && [ "${{ needs.plan.outputs.plan.tier }}" != "pr" ]; then + # Keep Perry's bin/unit tests in the full workspace lane. Its + # large integration inventory runs separately on the full tier. echo "::group::cargo test --bins -p perry" cargo test --bins -p perry else @@ -1698,7 +1687,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Install sccache @@ -2082,7 +2071,7 @@ jobs: # and an MSVC-only link error (LNK2019: `js_crypto_ed25519_verify` # unresolved when linking perry.exe — Unix linkers dead-strip the unused # extern, link.exe errors). Building `perry` LINKS perry.exe, so the LNK2019 - # class is caught here, not just rustc errors. The perry-dev profile + # class is caught here, not just rustc errors. The dev profile # (opt-level 1, no LTO) keeps a cold Windows build inside a PR-sized budget; # --release would be far too slow for per-PR CI. # --------------------------------------------------------------------------- @@ -2146,7 +2135,7 @@ jobs: python benchmarks/gc_ratchet/gc_ratchet.py validate --scope structural - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Setup Node.js @@ -2159,14 +2148,14 @@ jobs: shared-key: "${{ runner.os }}-perry" save-if: ${{ github.ref == 'refs/heads/main' }} - # perry-dev (see Cargo.toml [profile.perry-dev]) trades peak optimization + # dev (see Cargo.toml [profile.dev]) trades peak optimization # for build speed. The package set covers the compiler binary (link # gate), the runtime/stdlib pair (the usual source of cfg(windows) # externs), their static-library wrappers (used by the parity smoke # below), and both Windows UI crates — the ones cargo-test's ubuntu # runner must exclude and therefore never compiles. - - name: Build compiler + runtime + Windows UI crates (perry-dev) - run: cargo build --profile perry-dev -p perry -p perry-runtime -p perry-stdlib -p perry-runtime-static -p perry-stdlib-static -p perry-ui-windows -p perry-ui-windows-winui + - name: Build compiler + runtime + Windows UI crates (dev) + run: cargo build --profile dev -p perry -p perry-runtime -p perry-stdlib -p perry-runtime-static -p perry-stdlib-static -p perry-ui-windows -p perry-ui-windows-winui # #7356: the full perry-runtime --lib suite is green on Windows for the # first time (the SEH/longjmp transport, setjmp alignment, TZ, trim and @@ -2175,12 +2164,12 @@ jobs: # arm that keeps the suite green rather than letting it rot back to # "unmeasurable". Single-threaded for the same #1444 process-global-state # reason as the ubuntu leg (both its invocations set RUST_TEST_THREADS=1); - # perry-dev profile so the test build shares the dependency artifacts the + # dev profile so the test build shares the dependency artifacts the # build step above already produced instead of paying a second cold # dev-profile build of a ~340k-line crate. - name: perry-runtime unit tests (single-threaded, #7356) shell: bash - run: RUST_TEST_THREADS=1 cargo test --profile perry-dev --lib -p perry-runtime + run: RUST_TEST_THREADS=1 cargo test --profile dev --lib -p perry-runtime - name: Windows runtime regressions against pinned Node run: python scripts/run_windows_runtime_regressions.py @@ -2192,8 +2181,8 @@ jobs: shell: bash run: | PERRY_SKIP_BUILD=1 \ - PERRY_BIN="$PWD/target/perry-dev/perry.exe" \ - PERRY_RUNTIME_DIR="$PWD/target/perry-dev" \ + PERRY_BIN="$PWD/target/debug/perry.exe" \ + PERRY_RUNTIME_DIR="$PWD/target/debug" \ ./run_parity_tests.sh \ --suite node-suite \ --module process \ @@ -2203,7 +2192,7 @@ jobs: shell: pwsh run: | $ErrorActionPreference = 'Stop' - $binary = 'target/perry-dev/perry.exe' + $binary = 'target/debug/perry.exe' $metadata = cargo metadata --no-deps --format-version 1 | ConvertFrom-Json $expectedVersion = ($metadata.packages | Where-Object name -eq 'perry').version $version = (Get-Item $binary).VersionInfo @@ -2228,7 +2217,7 @@ jobs: shell: bash run: | set -o pipefail - cargo test --profile perry-dev -p perry --bin perry \ + cargo test --profile dev -p perry --bin perry \ coff_archive_dedup_drops_only_fully_provided_members 2>&1 | tee test-output.log grep -q 'test result: ok. 1 passed; 0 failed' test-output.log || { echo "::error::expected COFF dedup test did not run exactly once" @@ -2270,7 +2259,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Set up ARM64 MSVC environment @@ -2287,11 +2276,11 @@ jobs: shared-key: "${{ runner.os }}-${{ runner.arch }}-perry" save-if: ${{ github.ref == 'refs/heads/main' }} - - name: Build ARM64 compiler and static libraries (perry-dev) - run: cargo build --profile perry-dev -p perry -p perry-runtime-static -p perry-stdlib-static + - name: Build ARM64 compiler and static libraries (dev) + run: cargo build --profile dev -p perry -p perry-runtime-static -p perry-stdlib-static - name: Run ARM64 setjmp ABI tests - run: 'cargo test --profile perry-dev --lib -p perry-runtime ffi::setjmp::tests:: -- --test-threads=1' + run: 'cargo test --profile dev --lib -p perry-runtime ffi::setjmp::tests:: -- --test-threads=1' - name: Compile and run a Perry ARM64 executable shell: pwsh @@ -2301,9 +2290,9 @@ jobs: # composition has its own gate; this job's contract is the ARM ABI, # target selection, SDK discovery, final PE link, and execution. New-Item -ItemType Directory -Force 'target/windows-arm64-smoke-libs' | Out-Null - Copy-Item 'target/perry-dev/perry_runtime.lib' 'target/windows-arm64-smoke-libs/' + Copy-Item 'target/debug/perry_runtime.lib' 'target/windows-arm64-smoke-libs/' $env:PERRY_RUNTIME_DIR = (Resolve-Path 'target/windows-arm64-smoke-libs').Path - target/perry-dev/perry.exe compile tests/release/link_smoke/fixture.ts ` + target/debug/perry.exe compile tests/release/link_smoke/fixture.ts ` --target windows-aarch64 ` --no-auto-optimize ` -o target/windows-arm64-smoke.exe @@ -2363,7 +2352,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 with: @@ -2446,7 +2435,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 with: @@ -2563,7 +2552,7 @@ jobs: # The remaining GC stress arms are aggregate-only. Repeating them in # every matrix shard would add cost without increasing their coverage. - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 with: @@ -2674,7 +2663,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Install sccache @@ -3047,7 +3036,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Install sccache @@ -3239,7 +3228,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Install sccache @@ -3347,7 +3336,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 @@ -3457,7 +3446,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 @@ -3688,7 +3677,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 with: @@ -3773,7 +3762,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 with: @@ -3988,7 +3977,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 @@ -4408,7 +4397,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 @@ -4490,7 +4479,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 @@ -4591,7 +4580,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 @@ -4665,7 +4654,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 @@ -4846,7 +4835,7 @@ jobs: echo "Disk free: ${BEFORE} -> ${AFTER}" - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - name: Set up MSVC environment (Windows) @@ -5059,7 +5048,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 diff --git a/.github/workflows/tls-budget.yml b/.github/workflows/tls-budget.yml index c4c724476a..b7ab3e5a7c 100644 --- a/.github/workflows/tls-budget.yml +++ b/.github/workflows/tls-budget.yml @@ -200,7 +200,7 @@ jobs: - name: Install Rust toolchain if: steps.relevance.outputs.run == 'true' - run: rustup toolchain install nightly-2026-08-20 --profile minimal + run: rustup toolchain install nightly-2026-10-04 --profile minimal - uses: ./.github/actions/setup-llvm22 if: steps.relevance.outputs.run == 'true' diff --git a/.github/workflows/wasi-check.yml b/.github/workflows/wasi-check.yml index 9ed3a76d9d..6675e90c3a 100644 --- a/.github/workflows/wasi-check.yml +++ b/.github/workflows/wasi-check.yml @@ -105,7 +105,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain with the WASI target - run: rustup toolchain install nightly-2026-08-20 --profile minimal --target wasm32-wasip2 + run: rustup toolchain install nightly-2026-10-04 --profile minimal --target wasm32-wasip2 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 with: @@ -158,7 +158,7 @@ jobs: git config http.https://github.com/.extraheader "$auth_header" fi - name: Install Rust toolchain with the WASI target - run: rustup toolchain install nightly-2026-08-20 --profile minimal --target wasm32-wasip2 + run: rustup toolchain install nightly-2026-10-04 --profile minimal --target wasm32-wasip2 - uses: ./.github/actions/setup-llvm22 - uses: ./.github/actions/perry/Swatinem/rust-cache # v2 diff --git a/CLAUDE.md b/CLAUDE.md index ffb9f29643..33d9195c9f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -80,13 +80,15 @@ PRs from outside contributors should **not** touch `[workspace.package] version` ### Which profile to use -- **Local dev / testing (default choice)**: `cargo check -p perry` for fastest feedback, then `cargo build --profile perry-dev -p perry` (opt-level=1, codegen-units=16, incremental, no LTO — minutes instead of ~30). Use this for iterating on the compiler, running gap/parity tests, and reproducing bugs. Only fall back to `--release` if a bug is optimization-sensitive. -- **Shipping / official artifacts**: `--profile dist` (mirrors `release`: thin LTO, codegen-units=1, opt-level=3, strip). Slow by design — LLVM codegen runs single-threaded per crate at codegen-units=1, and the giant crates (perry-runtime ~340k lines, perry-codegen, perry-hir) serialize the build regardless of core count. Don't use it for iteration. -- **Local release-ish build when you need release perf**: override the compile-time killer, keep the optimization: `CARGO_PROFILE_RELEASE_CODEGEN_UNITS=16 cargo build --release` (2–4× faster, ~1–3% runtime cost). +- **Local dev / testing (default choice)**: `cargo check -p perry` for type-check feedback, `make build-dev` for a fast debuggable binary, or `cargo build --profile perry-dev -p perry` when a specialized CI job expects `target/perry-dev`. The `dev` profile emits the debug build under `target/debug`, includes debug info/assertions, and keeps Perry's panic=abort runtime contract. Use `make build-prod` for an optimized local binary (opt-level 3, ThinLTO, parallel codegen). Both Make targets use Mr Boxington's cache; `prod` is for release-sensitive reproduction. +- **Shipping / official artifacts**: `--profile prod` (ThinLTO, 16 codegen units, opt-level 3, strip). The extra codegen units parallelize initial code generation while ThinLTO keeps cross-unit optimization. `make build-prod` uses Mr Boxington's shared compilation cache; use `make build-dev` for iteration. +- **Compatibility profiles**: `release`, `dist`, and `perry-dev` remain for existing tools and investigations. Prefer `dev` or `prod` for new commands. ```bash cargo build --release # Build all crates -cargo build --profile perry-dev -p perry # Fast local dev build (#5422; perry-dev profile) +cargo build -p perry # Fast debug build (target/debug) +cargo build --profile perry-dev -p perry # Optimized dev compatibility build +cargo build --profile prod -p perry # Fully optimized local build cargo build --release -p perry-runtime -p perry-stdlib # Rebuild runtime (MUST rebuild stdlib too!) cargo build --release -p perry-runtime-static -p perry-stdlib-static # Emit libperry_{runtime,stdlib}.a (#5422: runtime/stdlib are now rlib-only; the .a comes from these wrapper crates) RUST_TEST_THREADS=1 cargo test --release -p perry-runtime # MUST be single-threaded (see below) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cc4a0fef54..a57f7cd4ce 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -55,12 +55,13 @@ under `crates/*/tests/`; CI runs those through its scoped and nightly jobs. Never replace it with `cargo test --workspace`: Perry's per-crate feature sets must remain isolated. -For a faster inner loop, `cargo check -p perry` (correctness only) or -`cargo build --profile perry-dev -p perry` (optimized local dev build). The +For a faster inner loop, use `cargo check -p perry` (correctness only), +`make build-dev` (fast debug build), or `make build-prod` (opt-level 3 with +ThinLTO and parallel codegen). The `.a` static archives now come from dedicated wrapper crates — build them with -`cargo build --release -p perry-runtime-static -p perry-stdlib-static` when you +`cargo build --profile prod -p perry-runtime-static -p perry-stdlib-static` when you need `libperry_{runtime,stdlib}.a`. See `docs/src/contributing/building.md` for -the full dev/release/dist taxonomy and the slim `--features dev-cli` CLI (#5422). +the full dev/prod profile guide and the slim `--features dev-cli` CLI (#5422). The full README [Development](README.md#development) section has more `cargo run` recipes (HIR dumps, per-crate rebuilds). diff --git a/Cargo.toml b/Cargo.toml index 12f78b0181..05865022ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -206,29 +206,67 @@ codegen-units = 1 [profile.release.package.perry-ext-ws] codegen-units = 1 -# Fast developer profile (#5422). Optimized enough for realistic local runs but -# without the distribution-grade settings that dominate compile time, so the -# edit/build loop stays short. Intended local loop: -# cargo check -p perry # fastest correctness feedback -# cargo build --profile perry-dev -p perry # optimized local development +# Fast developer profile. Keep Cargo's standard `dev` profile genuinely quick +# and debuggable; `perry-dev` remains as a compatibility profile for CI and +# scripts that rely on its established target/perry-dev artifact directory. +# Debug info and assertions stay enabled, but panic=abort keeps compiled Perry +# runtime archives on the same exception-transport strategy as production. +[profile.dev] +lto = false +codegen-units = 256 +incremental = true +debug = true +debug-assertions = true +strip = false +opt-level = 0 +panic = "abort" + +[profile.dev.package.perry-runtime] +opt-level = 0 +codegen-units = 256 + +[profile.dev.package.perry-stdlib] +opt-level = 0 + +# Optimized local developer profile retained for existing tests and CI. [profile.perry-dev] inherits = "release" lto = false -codegen-units = 1 +codegen-units = 16 incremental = true strip = false opt-level = 1 -# Official distribution profile (#5422). The explicit, named home for the -# release-grade optimization Perry ships. Mirrors [profile.release] exactly — -# including every per-package override below — so official artifacts stay -# equivalent while being selected via `--profile dist`. Keep these blocks in +# The release profile raises the large runtime crate back to opt-level 3 and +# one codegen unit. Restore the fast developer settings for local compiler +# iteration; `prod`, `dist`, and `release` retain shipping optimizations. +[profile.perry-dev.package.perry-runtime] +opt-level = 1 +codegen-units = 16 + +# Optimized production build. It inherits release/distribution settings and +# package overrides except for its parallel codegen-unit count, while writing +# to target/prod/ to keep artifacts distinct. Official release workflows and +# local builds use this profile; +# `dist` remains as a compatibility name for existing scripts. +[profile.prod] +inherits = "dist" +# Keep opt-level 3 and ThinLTO, but split initial code generation so rustc can +# compile LLVM modules in parallel. ThinLTO still optimizes across codegen +# units; using one unit was measurably expensive on large crates. +codegen-units = 16 + +# Production base profile (#5422). The explicit, named home for the release- +# grade optimization Perry ships. `prod` inherits these exact settings and +# package overrides under its standard name. It retains [profile.release]'s +# optimization level, ThinLTO, panic strategy, and package overrides; prod +# overrides codegen-units to parallelize compilation. Keep package blocks in # sync with their [profile.release.*] counterparts above. [profile.dist] inherits = "release" lto = "thin" codegen-units = 1 -# MUST match [profile.release] (#7302). `dist` is what release-packages.yml +# MUST match [profile.release] (#7302). `prod` is what release-packages.yml # builds the SHIPPED libperry_{runtime,stdlib}.a with, and the exception # transport requires the unwinder to step runtime Rust frames with # longjmp-equivalent semantics. Under panic="unwind" rustc plants RFC-2945 diff --git a/Makefile b/Makefile index cf4537d19e..844171d45f 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,8 @@ # Dev-facing targets. Perry is plain cargo (no mise), so this is intentionally # minimal — add targets here only when a plain `cargo ` isn't enough. +RUSTUP_TOOLCHAIN := $(shell sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml) +CARGO_BIN := $(if $(CARGO_HOME),$(CARGO_HOME),$(HOME)/.cargo)/bin +LLVM_SYS_221_PREFIX ?= $(shell brew --prefix llvm@22 2>/dev/null) # Apply clippy's machine-applicable autofixes across the workspace via # cargo-fixit (crate-ci/cargo-fixit, pinned in external-tools.json under the @@ -12,7 +15,7 @@ # `scripts/fleet/lint-rust.mts --fix`. .PHONY: fix fix: - @set -e; cargo fixit --clippy --workspace --all-targets --allow-dirty --allow-staged + @set -e; PATH="$(CARGO_BIN):$$PATH" cargo fixit --clippy --workspace --all-targets --allow-dirty --allow-staged # Install the pinned cargo-fixit dev tool that `make fix` drives. cargo-fixit # is a cargo crate with NO prebuilt binaries (no cargo binstall, no GitHub @@ -22,4 +25,24 @@ fix: .PHONY: fix-deps fix-deps: @set -e; v=$$(node -e "console.log(require('./external-tools.json').tools['cargo-fixit'].version)"); \ - cargo install cargo-fixit@$$v --locked + rustup run $(RUSTUP_TOOLCHAIN) cargo install cargo-fixit@$$v --locked + +# Install the pinned Mr Boxington Cargo cache used by build-dev/build-prod. +.PHONY: mbx-deps +mbx-deps: + @set -e; v=$$(node -e "console.log(require('./external-tools.json').tools.mbx.version)"); \ + rustup run $(RUSTUP_TOOLCHAIN) cargo install mbx@$$v --locked + +# Local iteration. The dev profile prioritizes quick, debuggable builds; +# prod uses opt-level 3 and ThinLTO with parallel codegen units. Leave +# MBX_INCREMENTAL unset: mbx keeps learned +# incremental state for edited crates while retaining shared-cache reuse for +# unchanged dependencies. Explicit Cargo incremental mode disables that sharing. +.PHONY: build-dev build-fast build-prod +build-dev: + PATH="$(CARGO_BIN):$$PATH" LLVM_SYS_221_PREFIX="$(LLVM_SYS_221_PREFIX)" mbx build --profile dev -p perry + +build-fast: build-dev + +build-prod: + PATH="$(CARGO_BIN):$$PATH" LLVM_SYS_221_PREFIX="$(LLVM_SYS_221_PREFIX)" mbx build --profile prod -p perry diff --git a/crates/perry/src/panic_profile_contract.rs b/crates/perry/src/panic_profile_contract.rs index ba765672fc..e278014c89 100644 --- a/crates/perry/src/panic_profile_contract.rs +++ b/crates/perry/src/panic_profile_contract.rs @@ -17,9 +17,10 @@ //! //! 1. `[profile.release]` itself was on the default (`unwind`) — closed by //! #7302. -//! 2. `[profile.dist]` (what `release-packages.yml` builds the SHIPPED -//! `libperry_{runtime,stdlib}.a` with) *inherits* `release` but then -//! re-declared `panic = "unwind"`, which wins. Every local build, every +//! 2. `[profile.dist]` is the compatibility base inherited by `[profile.prod]` +//! (what `release-packages.yml` now builds the SHIPPED +//! `libperry_{runtime,stdlib}.a` with). It once re-declared +//! `panic = "unwind"`, which won over `release`. Every local build, every //! CI job and the whole parity suite were correct while the artifact //! users install aborted on the first cross-helper throw. //! 3. A **separate workspace** in the tree — @@ -54,8 +55,8 @@ //! a `[workspace]` table that does not `exclude` it (or via an explicit //! `package.workspace` pointer), so the audit attributes members the same //! way instead of resolving `members` globs. -//! * **`inherits` chains are followed**, so `[profile.dist] inherits = -//! "release"` is judged by what it actually resolves to. +//! * **`inherits` chains are followed**, so `[profile.prod] inherits = +//! "dist"` is judged by what it actually resolves to. //! * **`dev-dependencies` are not an edge.** A dev-dependency is linked only //! into test/bench harnesses, and cargo ignores `panic` for those profiles //! outright — such a workspace cannot emit a shipped runtime archive. @@ -87,9 +88,9 @@ mod tests { /// gitignored). Everything else — including `node_modules` — is walked. const PRUNED_DIRS: &[&str] = &["target"]; - /// Profiles the main workspace ships runtime archives with, asserted by - /// name so a rename cannot silently drop one from the audit. - const MAIN_SHIPPING_PROFILES: &[&str] = &["release", "dist", "perry-dev"]; + /// Profiles that can produce runtime archives with the shipped panic + /// strategy, asserted by name so a rename cannot silently drop one. + const MAIN_ABORT_RUNTIME_PROFILES: &[&str] = &["dev", "release", "prod", "dist", "perry-dev"]; fn repo_root() -> PathBuf { let path = Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/../..")); @@ -531,11 +532,11 @@ mod tests { ); } - /// The main workspace's shipping profiles are also pinned BY NAME, so + /// The main workspace's runtime profiles are also pinned BY NAME, so /// renaming or deleting one cannot quietly shrink what the audit above /// judges. #[test] - fn main_workspace_shipping_profiles_exist_and_abort() { + fn main_workspace_abort_runtime_profiles_exist_and_abort() { let root = repo_root(); let manifests = collect_manifests(&root); let main = manifests @@ -543,11 +544,11 @@ mod tests { .expect("the repo root Cargo.toml must parse"); let profiles = profiles_of(main).expect("the repo root must declare [profile.*]"); - for name in MAIN_SHIPPING_PROFILES { + for name in MAIN_ABORT_RUNTIME_PROFILES { assert!( profiles.contains_key(*name), "[profile.{name}] has disappeared from the workspace manifest; if it was \ - renamed, update MAIN_SHIPPING_PROFILES so the rename is judged too" + renamed, update MAIN_ABORT_RUNTIME_PROFILES so the rename is judged too" ); match resolve_panic(Some(profiles), name) { Panic::Declared { value, by } => assert_eq!( diff --git a/crates/perry/tests/function_apply_dynamic_args_eval_surface.rs b/crates/perry/tests/function_apply_dynamic_args_eval_surface.rs index 4c1f7ec454..57deeae835 100644 --- a/crates/perry/tests/function_apply_dynamic_args_eval_surface.rs +++ b/crates/perry/tests/function_apply_dynamic_args_eval_surface.rs @@ -42,9 +42,9 @@ fn workspace_root() -> PathBuf { } /// #8479: `release`, not `debug`. `panic` is a PROFILE-level setting and only -/// `release`/`dist`/`perry-dev` set `panic = "abort"`. A debug archive is -/// `panic = "unwind"`, and under that strategy rustc plants an RFC-2945 -/// abort-on-unwind guard in every `extern "C"` helper — which a JS throw +/// `dev`/`release`/`prod`/`dist`/`perry-dev` set `panic = "abort"`. An unwind +/// archive makes rustc plant an RFC-2945 abort-on-unwind guard in every +/// `extern "C"` helper — which a JS throw /// crossing that helper trips ("panic in a function that cannot unwind"). /// Perry never ships such a runtime, so linking one here tested unwind /// semantics that do not exist in production and made this test and diff --git a/docs/src/contributing/building.md b/docs/src/contributing/building.md index e8b700795b..5601cc1006 100644 --- a/docs/src/contributing/building.md +++ b/docs/src/contributing/building.md @@ -2,10 +2,10 @@ ## Prerequisites -- Rust toolchain (stable, **≥ 1.94**): [rustup.rs](https://rustup.rs/). The - workspace pins no toolchain file, so an older `stable` fails with a - `sqlx@0.9.0 requires rustc 1.94.0` MSRV error from deep in the dependency - graph. `rustup update stable` resolves it. +- Rust toolchain: install [rustup](https://rustup.rs/); the workspace pins + `nightly-2026-10-04` in `rust-toolchain.toml` because its exception transport + needs nightly unwind-table flags. Running Cargo from the checkout installs + or selects the pinned toolchain automatically. - System C compiler (`cc` on macOS/Linux, MSVC on Windows) - **libclang** — the `libsqlite3-sys` build script runs `bindgen`. Missing it aborts the build with `Unable to find libclang`. Install `libclang-dev` @@ -18,6 +18,8 @@ `llvm-config` is not on `PATH`, set `LLVM_SYS_221_PREFIX` to the LLVM 22 prefix. On Windows this variable is mandatory and must point at the extracted LLVM 22 development archive used by the build. +- For the cached Make targets, install the pinned Mr Boxington once with + `make mbx-deps`. An external clang is not part of the normal in-process codegen path. Install a matching clang only when working on a path that explicitly invokes it (for @@ -30,35 +32,50 @@ example Windows host `--embed`) or when building with git clone https://github.com/PerryTS/perry.git cd perry -# Build the default product and its dependency closure -cargo build --release +# Build the fully optimized product and its dependency closure +make build-prod ``` -The binary is at `target/release/perry`. +The binary is at `target/prod/perry`. The workspace deliberately defaults to the `perry` CLI. Bindings, platform adapters, test support, and release-only archives are selected explicitly by their CI/release jobs. Workspace-wide host commands must use the centralized platform exclusions described in the [crate policy](crate-policy.md). -## Build taxonomy (dev / release / dist) +## Build taxonomy (dev / prod, with compatibility profiles) -Perry has three build profiles, each tuned for a different job (#5422): +Use `dev` and `prod` for new builds. Cargo's `debug` output directory is the +artifact directory for the `dev` profile; it is not a separate Cargo profile. +The legacy `perry-dev`, `release`, and `dist` profile names remain for existing +CI, tooling, and reproducible investigations. | Goal | Command | Profile | |------|---------|---------| | Fastest correctness feedback | `cargo check -p perry` | — | -| Optimized **local** development | `cargo build --profile perry-dev -p perry` | `perry-dev` | +| Fast, debuggable local development | `make build-dev` (or `cargo build --profile dev -p perry`) | `dev` | +| Optimized local development / CI | `cargo build --profile perry-dev -p perry` | `perry-dev` | +| Fully optimized local production build | `make build-prod` | `prod` | | Release-compatible build | `cargo build --release` | `release` | -| Official distribution artifacts | `cargo build --profile dist ...` | `dist` | - +| Official distribution artifacts | `cargo build --profile prod ...` | `prod` | + +- **`dev`** keeps debug info and prioritizes compilation speed (`opt-level = 0`, + `codegen-units = 256`, debug assertions on, and no LTO). Direct Cargo builds + use Cargo incremental compilation; `make build-dev` lets mbx manage learned + incremental state while preserving shared-cache reuse for matching outputs. + It keeps `panic = "abort"` so locally built Perry runtime archives preserve + the production exception transport contract. `make build-dev` + routes through Mr Boxington. Output is at `target/debug/perry`. - **`perry-dev`** inherits `release` but disables the expensive distribution settings (`lto = false`, `codegen-units = 16`, `opt-level = 1`, `incremental = true`, no strip) so the edit/build loop stays short. Output is at `target/perry-dev/perry`. -- **`dist`** mirrors `release` exactly (ThinLTO, `codegen-units = 1`, - `opt-level = 3`, strip) and is the explicit, named profile the release - workflows use for shipped artifacts. Output is at `target/dist/`. +- **`prod`** inherits the optimized distribution settings (ThinLTO, + `opt-level = 3`, strip) and uses 16 codegen units to parallelize compilation. + ThinLTO still optimizes across those units. Release workflows and + `make build-prod` use Mr Boxington and write to `target/prod/`. +- **`dist`** is retained as a compatibility profile with the same optimized + settings. New build commands should use `prod`. After a `--timings` build, `scripts/cargo_timing_summary.py` prints the slowest units so build-time regressions are visible. @@ -91,16 +108,16 @@ flags, dependencies, and how much prior work the cache can reuse. ```bash # Runtime only (must rebuild stdlib too!) -cargo build --release -p perry-runtime -p perry-stdlib +cargo build --profile prod -p perry-runtime -p perry-stdlib # The .a static archives are emitted by separate wrapper crates (#5422), so a # plain `cargo build` no longer produces them as a side effect. Build them # explicitly when you need libperry_runtime.a / libperry_stdlib.a (e.g. to link # compiled programs without the auto-optimize rebuild): -cargo build --release -p perry-runtime-static -p perry-stdlib-static +cargo build --profile prod -p perry-runtime-static -p perry-stdlib-static # Codegen only -cargo build --release -p perry-codegen +cargo build --profile prod -p perry-codegen ``` > **Important**: When rebuilding `perry-runtime`, you must also rebuild `perry-stdlib` because `libperry_stdlib.a` embeds perry-runtime as a static dependency. diff --git a/docs/src/testing/ci-tiers.md b/docs/src/testing/ci-tiers.md index f580c0aff6..0a3d355b4c 100644 --- a/docs/src/testing/ci-tiers.md +++ b/docs/src/testing/ci-tiers.md @@ -13,7 +13,7 @@ python3 scripts/ci_plan.py --self-test # the policy's own invariants | tier | trigger | what it is for | fan-in job | |---|---|---|---| | **pr** | every `pull_request` push | the required gate. Small, fast, must be green on `main`. | `pr-gate` — **the only required status context** | -| **sweep** | every `push` to `main` (coalesced) **+ a two-hourly cron backstop** | post-merge truth for `main`: the PR tier unscoped plus the medium-weight jobs that do not fit the PR budget | `main-gate` | +| **sweep** | every `push` to `main` (coalesced) **+ a two-hourly cron backstop** | post-merge truth for `main`: unscoped unit/package tests plus medium-weight jobs; Perry's large integration inventory stays in the nightly/release full tier | `main-gate` | | **full** | nightly `schedule`, `v*` tags, `workflow_dispatch`, PRs labelled `run-extended-tests` | everything, incl. parity, compile-smoke, doc-tests, package smokes, the 24-shard auto-optimize gap suite | `full-suite-gate` — what `release-packages.yml` waits for | ## The job × tier matrix @@ -85,6 +85,38 @@ The `perry-ext-*` crates remain excluded from dependency fan-out unless directly changed. `scripts/ci_test_scope.py` owns this policy, with regression tests in `lint`. +## Rust test lanes and timeboxes + +Perry's Cargo suites use the same fast / mid / slow idea as socket-wheelhouse, +but their wall times are measured in minutes because Rust compilation and the +runtime-linked test binaries dominate these suites. The wheelhouse's 10s / 30s / +60s limits apply to its small Vitest lanes and should not be copied onto Cargo. + +| Lane | What runs | Expected time | Enforced timebox | +|---|---|---:|---:| +| **Fast** | PR-scoped crate unit tests (`--lib --bins`), plus the always-on FFI ABI unit check | `<10 min` for the scoped Cargo loop | `30 min` Cargo job cap; the PR gate targets `≤30 min` wall clock once queued. | +| **Mid** | Full workspace package tests on main sweeps, including Perry bin/unit tests; Perry integration tests are left to the slow lane | `<60 min` target; the prior full Cargo job measured `50–60 min` warm and `90–103 min` cold before removing Perry's serial integration inventory | `120 min` Cargo job cap. | +| **Slow** | Complete Perry integration inventory on nightly, release tags, and opt-in full runs; changed suites run through `e2e-scoped` on PRs | Eight round-robin shards | `120 min` per shard. The separate scoped e2e job applies `25 min` subprocess bounds where configured. | + +The hard caps are failure cutoffs, not performance goals. Although fast and mid +share the `cargo-test` job, its timeout comes from the planner tier: 30 minutes +for PR scope and 120 minutes for full workspace scope. A manual +`workflow_dispatch --tier pr` has full workspace scope without the sharded slow +lane, so it retains a 180-minute cap. The main sweep now runs Perry's bin/unit +target in the `cargo-test` job while the complete Perry integration inventory +stays in the nightly/release shards; this avoids repeating the expensive serial +integration loop on every merge without dropping it from the full-suite gate. +A run that approaches its cap should trigger a measured build/test optimization, +not a larger timeout. Keep +`RUST_TEST_THREADS=1` for `perry-runtime`: its tests share process-global GC, +arena, timer, and notification state. Keep `CARGO_BUILD_JOBS=1` for the +runtime-linked test binaries until runner memory measurements support increasing +it. The sccache-backed CI jobs set `CARGO_INCREMENTAL=0`, so sccache can reuse +compiler outputs. Mr Boxington-backed release jobs use mbx's default cache +policy instead; local `make build-dev` and `make build-prod` leave +`MBX_INCREMENTAL` unset so mbx can keep private incremental state for edited +crates while sharing unchanged compilations. + `e2e-scoped` runs integration suites selected by the diff, but its `SUITE_EXCLUSIONS` check is deliberately not scoped: whenever that list is nonempty, every core PR reruns each excluded exact test and fails if it no diff --git a/external-tools.json b/external-tools.json index 8d8fbe5445..1048d33568 100644 --- a/external-tools.json +++ b/external-tools.json @@ -2,21 +2,21 @@ "tools": { "rust": { "description": "Rust toolchain (rustc + cargo) — pinned exact version for every workflow, instead of floating on whatever `dtolnay/rust-toolchain@stable` resolves to at run time.", - "version": "nightly-2026-08-20", + "version": "nightly-2026-10-04", "release": "rustup-toolchain", "repository": "github:rust-lang/rust", "notes": [ "Pinned via `toolchain:` on every `dtolnay/rust-toolchain@stable` step in .github/workflows/*.yml. Bump by editing tools.rust.version here and re-running the same substitution across every workflow file.", "Integrity is rustup's own signed-manifest verification, not a second SRI hash — this entry just records the adopted version for the soak gate.", - "Nightly, not stable, because -Zmin-publish-age (.cargo/config.toml) is nightly-only on 1.98.0 — verified directly, not assumed.", - "Transition-to-stable target: Rust 1.100.0, late September 2026, per the min-publish-age stabilization PR (https://github.com/rust-lang/cargo/pull/17335, open) and tracking issue (https://github.com/rust-lang/cargo/issues/17009). Same target as socket-wheelhouse's canonical rust-toolchain.toml.", + "Nightly, not stable, because .cargo/config.toml enables rustc's nightly-only -Z use-sync-unwind flag for compact synchronous unwind tables.", + "Cargo stabilized min-publish-age in Rust 1.100 (https://github.com/rust-lang/cargo/pull/17335); the registry age policy remains in .cargo/config.toml without the former unstable opt-in.", "Already carries the algebraic_* float methods used in crates/perry-runtime/src/perf_histogram.rs — stable since 1.98.0, unrelated to the nightly pin above.", "Adopted 1 day after this nightly's cut, via soakBypass below." ], "soakBypass": { - "version": "nightly-2026-08-20", - "published": "2026-08-20", - "removable": "2026-08-27" + "version": "nightly-2026-10-04", + "published": "2026-10-04", + "removable": "2026-10-11" } }, "node": { @@ -240,10 +240,19 @@ "description": "cargo-fixit — crate-ci/cargo-fixit, the drop-in faster replacement for `cargo clippy --fix` (skips the re-check compile between fix rounds). Installed from source via `cargo install cargo-fixit@ --locked` because the crate publishes NO prebuilt binaries (no cargo binstall, no GitHub release assets). Backs the `make fix` target.", "release": "cargo-install", "crate": "cargo-fixit", - "version": "0.1.15", + "version": "0.1.17", "binary": "cargo-fixit", "repository": "github:crate-ci/cargo-fixit", - "notes": "From-source install — no prebuilt binaries. --locked respects the published Cargo.lock (the supply-chain control). make fix-deps reads this pin and runs cargo install cargo-fixit@0.1.15 --locked." + "notes": "From-source install — no prebuilt binaries. --locked respects the published Cargo.lock (the supply-chain control). make fix-deps reads this pin and runs cargo install cargo-fixit@0.1.17 --locked." + }, + "mbx": { + "description": "Mr Boxington shared Cargo build cache, pinned to match socket-wheelhouse. Uses GitHub Actions cache for release builds and learned incremental reuse for local edit loops.", + "release": "cargo-install", + "crate": "mbx", + "version": "1.22.0", + "binary": "mbx", + "repository": "github:jdx/mr-boxington", + "notes": "Install with cargo install mbx@1.22.0 --locked. CI uses Perry's specialized local composite action, backed by the sparse-vendored upstream mr-boxington-action at a recorded immutable commit." } } } diff --git a/package-lock.json b/package-lock.json index a0e5bd1b19..5cc1989750 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "claude-fix-11244", + "name": "perry", "lockfileVersion": 3, "requires": true, "packages": { @@ -22,18 +22,61 @@ "nanoid": "^6.0.1", "rate-limiter-flexible": "^11.2.0", "redis": "6.1.0", + "run-local-ci": "0.18.1", "slugify": "^1.6.9", "uuid": "^14.0.2", "validator": "^13.15.35", "zod": "^4.3.5" } }, + "node_modules/@actions/expressions": { + "version": "0.3.61", + "resolved": "https://registry.npmjs.org/@actions/expressions/-/expressions-0.3.61.tgz", + "integrity": "sha512-Ig+tXELvTjlqxQAWBQnLNn2dPpNraLMdSnT+vDzDPmJtbNUhIAH/Z9kVT8pZ8UtJi9vUGs8hwHE8JFJmbOnLEA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@actions/workflow-parser": { + "version": "0.3.43", + "resolved": "https://registry.npmjs.org/@actions/workflow-parser/-/workflow-parser-0.3.43.tgz", + "integrity": "sha512-hghYVU7h//IGf+NaQgZrO7SI2Pre88ZKZQ8sM/1CBx1bEIJM9t9MMAeTCnKOknNaxBScbDPmmpwil26DxKgMwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@actions/expressions": "^0.3.43", + "cronstrue": "^2.21.0", + "yaml": "^2.0.0-8" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/@adraffy/ens-normalize": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz", "integrity": "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==", "license": "MIT" }, + "node_modules/@arr/every": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@arr/every/-/every-1.0.1.tgz", + "integrity": "sha512-UQFQ6SgyJ6LX42W8rHCs8KVc0JS0tzVL9ct4XYedJukskYVWTo49tNiMEK9C2HTyarbNiT/RVIRSY82vH+6sTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@balena/dockerignore": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@balena/dockerignore/-/dockerignore-1.0.2.tgz", + "integrity": "sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/@fastify/ajv-compiler": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-4.0.6.tgz", @@ -151,6 +194,58 @@ "ipaddr.js": "^2.1.0" } }, + "node_modules/@grpc/grpc-js": { + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.5.tgz", + "integrity": "sha512-7VZM+SVdEcUUqSQeNI3zM8Qs/BhQKZndPo2h5VkYkAM8Iz0wJIa8mKV5ekQGqG8UUsnkQ0NMxIxwkIHYvj0qOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.8.0", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" + } + }, + "node_modules/@grpc/grpc-js/node_modules/@grpc/proto-loader": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.1.tgz", + "integrity": "sha512-wtF6h+DY6M3YaDBPAmvuuA6jV8Sif9MjtOI5euKFWRgCDl5PeDpPsHR9u2l6St5ceY8AZgoNDww5+HvEsXFsGg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.5.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz", + "integrity": "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@ioredis/commands": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.10.0.tgz", @@ -165,6 +260,17 @@ "dev": true, "license": "MIT" }, + "node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, "node_modules/@mongodb-js/saslprep": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.5.4.tgz", @@ -206,6 +312,79 @@ "dev": true, "license": "MIT" }, + "node_modules/@polka/url": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-0.5.0.tgz", + "integrity": "sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", + "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.2.tgz", + "integrity": "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/@redis/bloom": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-6.1.0.tgz", @@ -403,6 +582,42 @@ ], "license": "BSD-3-Clause" }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, "node_modules/atomic-sleep": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", @@ -444,6 +659,97 @@ "node": ">= 6.0.0" } }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/body-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/bson": { "version": "7.3.3", "resolved": "https://registry.npmjs.org/bson/-/bson-7.3.3.tgz", @@ -454,6 +760,104 @@ "node": ">=20.19.0" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buildcheck": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.7.tgz", + "integrity": "sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==", + "dev": true, + "optional": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true, + "license": "ISC" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/cluster-key-slot": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.1.tgz", @@ -464,6 +868,40 @@ "node": ">=0.10.0" } }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/cookie": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", @@ -478,6 +916,21 @@ "url": "https://opencollective.com/express" } }, + "node_modules/cpu-features": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.10.tgz", + "integrity": "sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "buildcheck": "~0.0.6", + "nan": "^2.19.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/cron": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/cron/-/cron-4.4.0.tgz", @@ -496,6 +949,16 @@ "url": "https://ko-fi.com/intcreator" } }, + "node_modules/cronstrue": { + "version": "2.59.0", + "resolved": "https://registry.npmjs.org/cronstrue/-/cronstrue-2.59.0.tgz", + "integrity": "sha512-YKGmAy84hKH+hHIIER07VCAHf9u0Ldelx1uU6EBxsRPDXIA1m5fsKmJfyC3xBhw6cVC/1i83VdbL4PvepTrt8A==", + "dev": true, + "license": "MIT", + "bin": { + "cronstrue": "bin/cli.js" + } + }, "node_modules/date-fns": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.4.0.tgz", @@ -542,6 +1005,16 @@ "node": ">=0.10" } }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -552,6 +1025,148 @@ "node": ">=6" } }, + "node_modules/docker-modem": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-5.0.7.tgz", + "integrity": "sha512-XJgGhoR/CLpqshm4d3L7rzH6t8NgDFUIIpztYlLHIApeJjMZKYJMz2zxPsYxnejq5h3ELYSw/RBsi3t5h7gNTA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.1.1", + "readable-stream": "^3.5.0", + "split-ca": "^1.0.1", + "ssh2": "^1.15.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/dockerode": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/dockerode/-/dockerode-5.0.1.tgz", + "integrity": "sha512-avsq/xk4YPIrn0CgleX5bjT9Y8IT1p9PxrNQ++RBQ2WEyFfHCTDsT9kmyxz+H/axnjAwg8wJWEIuPGOUuNupiA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@balena/dockerignore": "^1.0.2", + "@grpc/grpc-js": "^1.11.1", + "@grpc/proto-loader": "^0.7.13", + "docker-modem": "^5.0.7", + "protobufjs": "^7.3.2", + "tar-fs": "^2.1.4" + }, + "engines": { + "node": ">= 14.17" + } + }, + "node_modules/dtu-github-actions": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/dtu-github-actions/-/dtu-github-actions-0.18.1.tgz", + "integrity": "sha512-BoK1sWdcOMKq58aGaChMbEMhrOJ+2ZPvlvASFXFkduq++6k/ZYi5c9RXaeLXcuTRZDOj/5lvJR4+j93+BXepSw==", + "dev": true, + "license": "FSL-1.1-MIT", + "dependencies": { + "body-parser": "^2.3.0", + "minimatch": "^10.2.5", + "polka": "^0.5.2", + "zod": "^3.24.1" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/dtu-github-actions/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/ethers": { "version": "6.17.0", "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.17.0.tgz", @@ -712,6 +1327,23 @@ "node": ">=20" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "license": "MIT" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/generate-function": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", @@ -722,6 +1354,115 @@ "is-property": "^1.0.2" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/iconv-lite": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", @@ -739,6 +1480,34 @@ "url": "https://opencollective.com/express" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, "node_modules/ioredis": { "version": "5.11.1", "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.11.1.tgz", @@ -793,6 +1562,16 @@ "node": ">= 10" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-property": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", @@ -866,6 +1645,13 @@ ], "license": "MIT" }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", @@ -913,6 +1699,43 @@ "node": ">=12" } }, + "node_modules/matchit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/matchit/-/matchit-1.1.0.tgz", + "integrity": "sha512-+nGYoOlfHmxe5BW5tE0EMJppXEwdSf8uBA1GTZC7Q77kbT35+VKLYJMzVNWCHSsga1ps1tPYFtFyvxvKzWVmMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@arr/every": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.1.tgz", + "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", @@ -920,6 +1743,56 @@ "dev": true, "license": "MIT" }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true, + "license": "MIT" + }, "node_modules/moment": { "version": "2.31.0", "resolved": "https://registry.npmjs.org/moment/-/moment-2.31.0.tgz", @@ -1033,6 +1906,14 @@ "node": ">=8.0.0" } }, + "node_modules/nan": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.29.0.tgz", + "integrity": "sha512-GlGk3HIvitbvs+LT3g6XUP1kpirKNvmDFwF/bmo6XNWSb/eYEs/O4bfgIEIXCZ+lIOTS5xNwDvSGMw6FJdAhtA==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/nanoid": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-6.0.1.tgz", @@ -1052,6 +1933,19 @@ "node": "^22 || ^24 || >=26" } }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/on-exit-leak-free": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", @@ -1062,6 +1956,29 @@ "node": ">=14.0.0" } }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/pino": { "version": "10.3.1", "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", @@ -1102,6 +2019,17 @@ "dev": true, "license": "MIT" }, + "node_modules/polka": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/polka/-/polka-0.5.2.tgz", + "integrity": "sha512-FVg3vDmCqP80tOrs+OeNlgXYmFppTXdjD5E7I4ET1NjvtNmQrb1/mJibybKkb/d4NA7YWAr1ojxuhpL3FHqdlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^0.5.0", + "trouter": "^2.0.1" + } + }, "node_modules/process-warning": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.1.0.tgz", @@ -1119,6 +2047,41 @@ ], "license": "MIT" }, + "node_modules/protobufjs": { + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.6.tgz", + "integrity": "sha512-dYDWdjSl5RNb7SgPxGQcRU+GtvP7s2fpkrY0r432PcOIaZ0/rBcxEZnQN67iJhFuQiVw754JDoPruPCNdGsbjg==", + "dev": true, + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.1", + "@protobufjs/fetch": "^1.1.1", + "@protobufjs/float": "^1.0.2", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", + "@types/node": ">=13.7.0", + "long": "^5.3.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -1129,6 +2092,23 @@ "node": ">=6" } }, + "node_modules/qs": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/quick-format-unescaped": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", @@ -1143,6 +2123,37 @@ "dev": true, "license": "ISC" }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/real-require": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", @@ -1193,6 +2204,16 @@ "node": ">=4" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -1231,6 +2252,47 @@ "dev": true, "license": "MIT" }, + "node_modules/run-local-ci": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/run-local-ci/-/run-local-ci-0.18.1.tgz", + "integrity": "sha512-x+hLy4c4aP04lTd/cmogcJhuDJqakmX8mBIB4UrUMGrvdNbsK3nl6xGQaaQojjb4eeQAlf8hCXyl0qgj9rGyog==", + "dev": true, + "license": "FSL-1.1-MIT", + "dependencies": { + "@actions/workflow-parser": "0.3.43", + "dockerode": "^5.0.1", + "dtu-github-actions": "0.18.1", + "minimatch": "^10.2.5", + "yaml": "^2.8.3" + }, + "bin": { + "local-ci": "dist/native-launcher.js" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/safe-regex2": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-5.1.1.tgz", @@ -1308,6 +2370,89 @@ "dev": true, "license": "MIT" }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/slugify": { "version": "1.6.9", "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.9.tgz", @@ -1338,6 +2483,13 @@ "memory-pager": "^1.0.2" } }, + "node_modules/split-ca": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz", + "integrity": "sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==", + "dev": true, + "license": "ISC" + }, "node_modules/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", @@ -1364,6 +2516,24 @@ "url": "https://github.com/mysqljs/sql-escaper?sponsor=1" } }, + "node_modules/ssh2": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.17.0.tgz", + "integrity": "sha512-wPldCk3asibAjQ/kziWQQt1Wh3PgDFpC0XpwclzKcdT1vql6KeYxf5LIt4nlFkUeR8WuphYMKqUA56X4rjbfgQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "asn1": "^0.2.6", + "bcrypt-pbkdf": "^1.0.2" + }, + "engines": { + "node": ">=10.16.0" + }, + "optionalDependencies": { + "cpu-features": "~0.0.10", + "nan": "^2.23.0" + } + }, "node_modules/standard-as-callback": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", @@ -1371,6 +2541,84 @@ "dev": true, "license": "MIT" }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar-fs": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.5.tgz", + "integrity": "sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/thread-stream": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.2.0.tgz", @@ -1401,6 +2649,16 @@ "node": ">=20" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, "node_modules/tr46": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", @@ -1414,18 +2672,74 @@ "node": ">=18" } }, + "node_modules/trouter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/trouter/-/trouter-2.0.1.tgz", + "integrity": "sha512-kr8SKKw94OI+xTGOkfsvwZQ8mWoikZDd2n8XZHjJVZUARZT+4/VV6cacRS6CLsH9bNm+HFIPU1Zx4CnNnb4qlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "matchit": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/tslib": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", "license": "0BSD" }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true, + "license": "Unlicense" + }, + "node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "dev": true, + "license": "MIT", + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/undici-types": { "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "license": "MIT" }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, "node_modules/uuid": { "version": "14.0.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.2.tgz", @@ -1474,6 +2788,31 @@ "node": ">=18" } }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, "node_modules/ws": { "version": "8.21.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", @@ -1495,6 +2834,61 @@ } } }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/zod": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz", diff --git a/package.json b/package.json index 2dc2ef3812..4b5b886adb 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "nanoid": "^6.0.1", "rate-limiter-flexible": "^11.2.0", "redis": "6.1.0", + "run-local-ci": "0.18.1", "slugify": "^1.6.9", "uuid": "^14.0.2", "validator": "^13.15.35", diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 67011efe33..dfbf90a6a6 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -2,11 +2,9 @@ # dtolnay/rust-toolchain (#8550). Keep the three in sync: this file, # those workflows, and `external-tools.json`'s `rust` entry. # -# Why a dated nightly rather than stable: `.cargo/config.toml` sets -# `[unstable] min-publish-age`, cargo's dependency-resolution soak gate, -# which is nightly-only (rust-lang/cargo#17009). On stable, cargo silently -# ignores it with `warning: ignoring registry.global-min-publish-age -# without -Zmin-publish-age`, so the soak gate is inert. +# Why a dated nightly rather than stable: `.cargo/config.toml` uses the +# nightly-only rustc flag `-Z use-sync-unwind` for compact synchronous unwind +# tables. Pinning also keeps local builds aligned with CI. # # Why this file has to exist as well as the workflow inputs: those inputs # only govern jobs that go through the action. Nothing else does — a @@ -15,5 +13,5 @@ # `float_algebraic` methods, so without this file those builds fail with # E0658 while CI stays green. [toolchain] -channel = "nightly-2026-08-20" +channel = "nightly-2026-10-04" components = ["rustfmt", "clippy"] diff --git a/scripts/build_core_runtime.sh b/scripts/build_core_runtime.sh index d3022cf409..ac3d8ab76b 100644 --- a/scripts/build_core_runtime.sh +++ b/scripts/build_core_runtime.sh @@ -1,18 +1,25 @@ #!/usr/bin/env bash # Build the feature-trimmed unwind runtime without changing the ordinary archive. # Run in the same toolchain/sysroot as the full runtime. Optional second argument -# lets the verification campaign use release instead of the packaging profile. +# lets the verification campaign use release instead of the production profile. set -euo pipefail target="${1:?usage: build_core_runtime.sh TARGET [PROFILE]}" -profile="${2:-dist}" +profile="${2:-prod}" case "$target" in *-apple-darwin|*-unknown-linux-gnu|*-unknown-linux-musl) ;; *) echo "unsupported core runtime target: $target" >&2; exit 2 ;; esac ordinary_target_dir="${CARGO_TARGET_DIR:-target}" core_target_dir="${PERRY_CORE_TARGET_DIR:-${ordinary_target_dir}-core}" -CARGO_TARGET_DIR="$core_target_dir" cargo build --locked --profile "$profile" --target "$target" \ +profile_dir="$profile" +[[ "$profile" == "dev" ]] && profile_dir=debug +if command -v mbx >/dev/null 2>&1; then + cargo_build=(mbx build) +else + cargo_build=(cargo build) +fi +env CARGO_TARGET_DIR="$core_target_dir" "${cargo_build[@]}" --locked --profile "$profile" --target "$target" \ -p perry-runtime-static --no-default-features --features perry-runtime/prebuilt-core -mkdir -p "$ordinary_target_dir/$target/$profile" -cp "$core_target_dir/$target/$profile/libperry_runtime.a" \ - "$ordinary_target_dir/$target/$profile/libperry_runtime_core.a" +mkdir -p "$ordinary_target_dir/$target/$profile_dir" +cp "$core_target_dir/$target/$profile_dir/libperry_runtime.a" \ + "$ordinary_target_dir/$target/$profile_dir/libperry_runtime_core.a" diff --git a/scripts/build_linux_glibc_2_31.sh b/scripts/build_linux_glibc_2_31.sh index 548eaf44f1..a2a798a75f 100755 --- a/scripts/build_linux_glibc_2_31.sh +++ b/scripts/build_linux_glibc_2_31.sh @@ -58,15 +58,21 @@ command -v rustup >/dev/null || { rustup target add "$target" -cargo build --profile dist --target "$target" -p perry -cargo build --profile dist --target "$target" -p perry-runtime -p perry-runtime-static -cargo build --profile dist --target "$target" -p perry-stdlib -p perry-stdlib-static +if command -v mbx >/dev/null 2>&1; then + cargo_build=(mbx build) +else + cargo_build=(cargo build) +fi + +"${cargo_build[@]}" --profile prod --target "$target" -p perry +"${cargo_build[@]}" --profile prod --target "$target" -p perry-runtime -p perry-runtime-static +"${cargo_build[@]}" --profile prod --target "$target" -p perry-stdlib -p perry-stdlib-static # Ship the panic=abort runtime variant from the same old sysroot. -CARGO_TARGET_DIR="$abort_target_dir" CARGO_PROFILE_DIST_PANIC=abort \ - cargo build --profile dist --target "$target" -p perry-runtime -p perry-runtime-static -cp "$abort_target_dir/$target/dist/libperry_runtime.a" \ - "$target_dir/$target/dist/libperry_runtime_abort.a" +CARGO_TARGET_DIR="$abort_target_dir" CARGO_PROFILE_PROD_PANIC=abort \ + "${cargo_build[@]}" --profile prod --target "$target" -p perry-runtime -p perry-runtime-static +cp "$abort_target_dir/$target/prod/libperry_runtime.a" \ + "$target_dir/$target/prod/libperry_runtime_abort.a" # Build the optional feature subset inside the same glibc 2.31 sysroot. bash scripts/build_core_runtime.sh "$target" @@ -78,13 +84,13 @@ bash scripts/build_core_runtime.sh "$target" governed_ext_packages=$(./scripts/release_ext_packages.sh) while IFS= read -r package; do echo "::group::build $package" - cargo build --profile dist --target "$target" \ + "${cargo_build[@]}" --profile prod --target "$target" \ -p perry -p perry-runtime-static -p perry-stdlib-static -p "$package" \ || echo " (skipped $package -- failed to build on the glibc 2.31 sysroot)" echo "::endgroup::" done <<< "$governed_ext_packages" -compiler="$target_dir/$target/dist/perry" +compiler="$target_dir/$target/prod/perry" max_glibc=$( readelf --version-info "$compiler" \ | grep -oE 'GLIBC_[0-9]+(\.[0-9]+)+' \ diff --git a/scripts/build_linux_musl.sh b/scripts/build_linux_musl.sh index 55465e4747..93454a243a 100755 --- a/scripts/build_linux_musl.sh +++ b/scripts/build_linux_musl.sh @@ -98,22 +98,28 @@ test -s /opt/perry-musl/lib/libstdc++.a || { rustup target add "$target" -cargo build --profile dist --target "$target" -p perry -cargo build --profile dist --target "$target" -p perry-runtime -p perry-runtime-static -cargo build --profile dist --target "$target" -p perry-stdlib -p perry-stdlib-static +if command -v mbx >/dev/null 2>&1; then + cargo_build=(mbx build) +else + cargo_build=(cargo build) +fi + +"${cargo_build[@]}" --profile prod --target "$target" -p perry +"${cargo_build[@]}" --profile prod --target "$target" -p perry-runtime -p perry-runtime-static +"${cargo_build[@]}" --profile prod --target "$target" -p perry-stdlib -p perry-stdlib-static # Ship the panic=abort runtime variant from the same sysroot. -CARGO_TARGET_DIR="$abort_target_dir" CARGO_PROFILE_DIST_PANIC=abort \ - cargo build --profile dist --target "$target" -p perry-runtime -p perry-runtime-static -cp "$abort_target_dir/$target/dist/libperry_runtime.a" \ - "$target_dir/$target/dist/libperry_runtime_abort.a" +env CARGO_TARGET_DIR="$abort_target_dir" CARGO_PROFILE_PROD_PANIC=abort \ + "${cargo_build[@]}" --profile prod --target "$target" -p perry-runtime -p perry-runtime-static +cp "$abort_target_dir/$target/prod/libperry_runtime.a" \ + "$target_dir/$target/prod/libperry_runtime_abort.a" bash scripts/build_core_runtime.sh "$target" # A dynamically linked binary can run on the glibc build host and still fail # immediately for users on Alpine. Gate the artifact itself, not just the # Cargo exit status. -compiler="$target_dir/$target/dist/perry" +compiler="$target_dir/$target/prod/perry" # `file` 5.39 (Debian 11) calls static PIE "dynamically linked" merely because # it has a PT_DYNAMIC relocation table. Log its summary, but use the ELF # interpreter and dependency tables below as the portable pass/fail criteria. diff --git a/scripts/cargo_timing_summary.py b/scripts/cargo_timing_summary.py index b18c4f7d3f..354f9d468e 100755 --- a/scripts/cargo_timing_summary.py +++ b/scripts/cargo_timing_summary.py @@ -9,7 +9,7 @@ optimization settings. Usage: - cargo build --profile dist -p perry --timings + cargo build --profile prod -p perry --timings scripts/cargo_timing_summary.py # latest report, top 15 scripts/cargo_timing_summary.py --top 30 scripts/cargo_timing_summary.py path/to/cargo-timing.html diff --git a/scripts/check_gc_header_constants.py b/scripts/check_gc_header_constants.py index 056e201d9c..fac0c88104 100755 --- a/scripts/check_gc_header_constants.py +++ b/scripts/check_gc_header_constants.py @@ -29,7 +29,7 @@ class into `@perry_class_header_image_*`; and That compares codegen's constant to a string literal — a tautology. It is a useful "you edited the const, now fix the mask arithmetic below" pin, but it never references the runtime, so it cannot detect a renumbering there; and per -CLAUDE.md's profile note it is compiled out of `release` AND `perry-dev` +CLAUDE.md's profile note it is compiled out of `release`, `prod`, AND `perry-dev` anyway. Every codegen test naming these bits asserts codegen's own constant appears in the emitted IR, so they pin codegen to itself and would all stay green. diff --git a/scripts/ci_plan.py b/scripts/ci_plan.py index f3c3e7b09c..8c7c8481ef 100755 --- a/scripts/ci_plan.py +++ b/scripts/ci_plan.py @@ -26,7 +26,9 @@ sweep every push to `main`, coalesced (at most one running + one pending, so a burst of merges is tested at its tip). The PR tier unscoped, plus the medium-weight jobs that do not fit the PR budget (Windows builds, - compiler-output gates, the full GC x repsel matrix, ...). + compiler-output gates, the full GC x repsel matrix, ...). Perry's + large integration inventory stays in the nightly/release full tier; + PR diffs still run their selected integration suites via e2e-scoped. full nightly, release tags, `workflow_dispatch` (the release pipeline's `await-tests` dispatches this and waits for the `full-suite-gate` job), and PRs carrying the `run-extended-tests` label. The sweep plus the diff --git a/scripts/node_compat_matrix.mjs b/scripts/node_compat_matrix.mjs index e0802f527f..26e22c0115 100644 --- a/scripts/node_compat_matrix.mjs +++ b/scripts/node_compat_matrix.mjs @@ -85,12 +85,9 @@ const MANIFEST_ENTRIES = path.join( 'src', 'entries.rs', ) -// The compiler binary. Two things the hardcoded `target/release/perry` got -// wrong on Windows (#10385): the executable is `perry.exe` there, so the -// matrix could never find it and died in its own precondition check; and -// Windows CI builds `--profile perry-dev`, not `--release`, so even a correct -// suffix would point at a path that job never produces. `PERRY_BIN` overrides -// both, matching the env the parity harness already honours. +// The standalone node-compat workflow builds the release profile. Include the +// platform executable suffix so local Windows runs resolve the same artifact; +// `PERRY_BIN` can point at another profile's build when needed. const PERRY_BIN = process.env.PERRY_BIN || path.join( @@ -463,7 +460,7 @@ async function runMatrix(args) { throw new Error( `perry release binary missing at ${PERRY_BIN}\n` + ` build it: cargo build --release -p perry\n` + - ` or point at an existing build: PERRY_BIN= (e.g. target/perry-dev/perry.exe)`, + ` or point at an existing build: PERRY_BIN= (e.g. target/debug/perry.exe)`, ) } const pin = loadNodePin() diff --git a/scripts/publish/brew/formula.mts b/scripts/publish/brew/formula.mts index b79beaf815..c40f613be1 100644 --- a/scripts/publish/brew/formula.mts +++ b/scripts/publish/brew/formula.mts @@ -68,10 +68,10 @@ export function renderPerryFormula(spec: PerryFormulaSpec): string { ' bin.install "perry"', ' lib.install Dir["libperry_*.a"]', ' else', - ' system "cargo", "build", "--release"', - ' system "cargo", "build", "--release", "-p", "perry-runtime", "-p", "perry-stdlib"', - ' bin.install "target/release/perry"', - ' lib.install Dir["target/release/libperry_*.a"]', + ' system "cargo", "build", "--profile", "prod"', + ' system "cargo", "build", "--profile", "prod", "-p", "perry-runtime", "-p", "perry-stdlib", "-p", "perry-runtime-static", "-p", "perry-stdlib-static"', + ' bin.install "target/prod/perry"', + ' lib.install Dir["target/prod/libperry_*.a"]', ' end', ' end', '', diff --git a/scripts/run_windows_runtime_regressions.py b/scripts/run_windows_runtime_regressions.py index 9f09cda63c..471eb07966 100644 --- a/scripts/run_windows_runtime_regressions.py +++ b/scripts/run_windows_runtime_regressions.py @@ -26,8 +26,8 @@ def run(command, env, timeout): def main(): parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--compiler", type=Path, default=ROOT / "target/perry-dev/perry.exe") - parser.add_argument("--runtime-dir", type=Path, default=ROOT / "target/perry-dev") + parser.add_argument("--compiler", type=Path, default=ROOT / "target/debug/perry.exe") + parser.add_argument("--runtime-dir", type=Path, default=ROOT / "target/debug") args = parser.parse_args() if os.name != "nt": parser.error("These regressions require a native Windows host") diff --git a/scripts/test-async-resource-own-bind.mjs b/scripts/test-async-resource-own-bind.mjs index 2efbf57d31..0d772ad316 100644 --- a/scripts/test-async-resource-own-bind.mjs +++ b/scripts/test-async-resource-own-bind.mjs @@ -8,7 +8,7 @@ import { prepareRequireRuntime } from './test-require-runtime.mjs'; const root = path.dirname(path.dirname(fileURLToPath(import.meta.url))); prepareRequireRuntime(root); -const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/perry-dev/perry'); +const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/debug/perry'); const work = fs.mkdtempSync(path.join(os.tmpdir(), 'perry-async-own-bind-')); const env = { ...process.env }; if (env.PERRY_TEST_WASM === '1' && env.PERRY_RUNTIME_DIR) delete env.PERRY_WORKSPACE_ROOT; diff --git a/scripts/test-bun-embedded-compression.mjs b/scripts/test-bun-embedded-compression.mjs index ab96b7b7e2..5c35ffdb5b 100644 --- a/scripts/test-bun-embedded-compression.mjs +++ b/scripts/test-bun-embedded-compression.mjs @@ -9,7 +9,7 @@ import { prepareRequireRuntime } from './test-require-runtime.mjs'; const repo = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); assert.equal(process.versions.node, fs.readFileSync(path.join(repo, '.node-version'), 'utf8').trim().replace(/^v/, '')); prepareRequireRuntime(repo); -const compiler = process.env.PERRY_BIN ?? path.join(repo, 'target/perry-dev/perry'); +const compiler = process.env.PERRY_BIN ?? path.join(repo, 'target/debug/perry'); const work = fs.mkdtempSync(path.join(os.tmpdir(), 'perry-bun-embedded-compression-')); const source = path.join(work, 'source'); fs.mkdirSync(source); diff --git a/scripts/test-bun-text-modules.mjs b/scripts/test-bun-text-modules.mjs index e371e45cfe..14d333b639 100644 --- a/scripts/test-bun-text-modules.mjs +++ b/scripts/test-bun-text-modules.mjs @@ -9,7 +9,7 @@ import { spawnSync } from 'node:child_process'; import { prepareRequireRuntime } from './test-require-runtime.mjs'; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); prepareRequireRuntime(root); -const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/perry-dev/perry'); +const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/debug/perry'); const work = fs.mkdtempSync(path.join(os.tmpdir(), 'perry-bun-text-')); const source = path.join(work, 'source'); fs.cpSync(path.join(root, 'tests/modules/bunfs_text_require'), source, { recursive: true }); diff --git a/scripts/test-child-output-late-iterator.mjs b/scripts/test-child-output-late-iterator.mjs index 4cf400fd42..d8ab2ca6c2 100644 --- a/scripts/test-child-output-late-iterator.mjs +++ b/scripts/test-child-output-late-iterator.mjs @@ -8,7 +8,7 @@ import { prepareRequireRuntime } from './test-require-runtime.mjs'; const root = path.dirname(path.dirname(fileURLToPath(import.meta.url))); prepareRequireRuntime(root); -const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/perry-dev/perry'); +const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/debug/perry'); const work = fs.mkdtempSync(path.join(os.tmpdir(), 'perry-child-late-iterator-')); const env = { ...process.env, PERRY_TEST_CHILD_EXECUTABLE: process.execPath, PERRY_TEST_MISSING_CHILD: path.join(work, 'definitely-absent-child') }; diff --git a/scripts/test-export-dollar-underscore-collision.mjs b/scripts/test-export-dollar-underscore-collision.mjs index 19712e9cdb..53c60804d2 100644 --- a/scripts/test-export-dollar-underscore-collision.mjs +++ b/scripts/test-export-dollar-underscore-collision.mjs @@ -7,7 +7,7 @@ import { fileURLToPath } from 'node:url'; import { spawnSync } from 'node:child_process'; const root = path.dirname(path.dirname(fileURLToPath(import.meta.url))); -const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/perry-dev/perry'); +const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/debug/perry'); const work = fs.mkdtempSync(path.join(os.tmpdir(), 'perry-export-collision-')); let passed = false; try { diff --git a/scripts/test-exported-local-storage.mjs b/scripts/test-exported-local-storage.mjs index 7bd4b5e443..9a0f6b0d01 100644 --- a/scripts/test-exported-local-storage.mjs +++ b/scripts/test-exported-local-storage.mjs @@ -7,7 +7,7 @@ import { fileURLToPath } from 'node:url'; import { spawnSync } from 'node:child_process'; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); -const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/perry-dev/perry'); +const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/debug/perry'); const work = fs.mkdtempSync(path.join(os.tmpdir(), 'perry-exported-local-storage-')); let passed = false; try { diff --git a/scripts/test-import-meta-require-value.mjs b/scripts/test-import-meta-require-value.mjs index e9a8da3c69..156ae2bbad 100644 --- a/scripts/test-import-meta-require-value.mjs +++ b/scripts/test-import-meta-require-value.mjs @@ -9,7 +9,7 @@ import { prepareRequireRuntime } from './test-require-runtime.mjs'; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); prepareRequireRuntime(root); -const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/perry-dev/perry'); +const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/debug/perry'); const work = fs.mkdtempSync(path.join(os.tmpdir(), 'perry-import-meta-require-value-')); let passed = false; try { diff --git a/scripts/test-imported-value-class-collision.mjs b/scripts/test-imported-value-class-collision.mjs index d27e7c0253..38c93a298e 100644 --- a/scripts/test-imported-value-class-collision.mjs +++ b/scripts/test-imported-value-class-collision.mjs @@ -7,7 +7,7 @@ import { fileURLToPath } from 'node:url'; import { spawnSync } from 'node:child_process'; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); -const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/perry-dev/perry'); +const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/debug/perry'); const work = fs.mkdtempSync(path.join(os.tmpdir(), 'perry-imported-value-class-collision-')); let passed = false; try { diff --git a/scripts/test-loop-lexical-tdz.mjs b/scripts/test-loop-lexical-tdz.mjs index c714ccf670..03ceea6fba 100644 --- a/scripts/test-loop-lexical-tdz.mjs +++ b/scripts/test-loop-lexical-tdz.mjs @@ -7,7 +7,7 @@ import { fileURLToPath } from 'node:url'; import { spawnSync } from 'node:child_process'; const root = path.dirname(path.dirname(fileURLToPath(import.meta.url))); -const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/perry-dev/perry'); +const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/debug/perry'); const work = fs.mkdtempSync(path.join(os.tmpdir(), 'perry-loop-tdz-')); let passed = false; try { diff --git a/scripts/test-minsize-inline-policy.mjs b/scripts/test-minsize-inline-policy.mjs index de4bfeeb8e..9bf43ad800 100644 --- a/scripts/test-minsize-inline-policy.mjs +++ b/scripts/test-minsize-inline-policy.mjs @@ -48,7 +48,7 @@ if (process.argv.includes('--self-test')) { process.exit(0); } prepareRequireRuntime(root); -const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/perry-dev/perry'); +const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/debug/perry'); const work = fs.mkdtempSync(path.join(os.tmpdir(), 'perry-minsize-inline-')); const source = path.join(work, 'fixture.ts'); fs.copyFileSync(path.join(root, 'test-files/test_gap_minsize_inline_policy.ts'), source); diff --git a/scripts/test-namespace-getter-binding-identity.mjs b/scripts/test-namespace-getter-binding-identity.mjs index c9b5722e86..17188d2939 100644 --- a/scripts/test-namespace-getter-binding-identity.mjs +++ b/scripts/test-namespace-getter-binding-identity.mjs @@ -7,7 +7,7 @@ import { fileURLToPath } from 'node:url'; import { spawnSync } from 'node:child_process'; const root = path.dirname(path.dirname(fileURLToPath(import.meta.url))); -const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/perry-dev/perry'); +const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/debug/perry'); const work = fs.mkdtempSync(path.join(os.tmpdir(), 'perry-namespace-getter-')); let passed = false; try { diff --git a/scripts/test-object-array-methods.mjs b/scripts/test-object-array-methods.mjs index 1cb3239a21..403672a1b8 100644 --- a/scripts/test-object-array-methods.mjs +++ b/scripts/test-object-array-methods.mjs @@ -7,7 +7,7 @@ import { fileURLToPath } from 'node:url'; import { spawnSync } from 'node:child_process'; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); -const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/perry-dev/perry'); +const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/debug/perry'); const work = fs.mkdtempSync(path.join(os.tmpdir(), 'perry-object-array-methods-')); let passed = false; try { diff --git a/scripts/test-require-runtime.mjs b/scripts/test-require-runtime.mjs index a232cecf1d..2f350f6286 100644 --- a/scripts/test-require-runtime.mjs +++ b/scripts/test-require-runtime.mjs @@ -13,10 +13,10 @@ export function prepareRequireRuntime(root) { if (prepared && !process.env.PERRY_RUNTIME_DIR) { throw new Error('Prepared require runtime needs an explicit PERRY_RUNTIME_DIR'); } - // perry-dev keeps panic=abort and avoids a second thin-LTO build inside - // cargo test. Release/dist remain available for optimization-sensitive runs. + // dev and perry-dev keep panic=abort without thin-LTO. Prod/release/dist + // remain available for fully optimized runtime checks. const profile = process.env.PERRY_TEST_RUNTIME_PROFILE ?? 'perry-dev'; - if (!['release', 'perry-dev', 'dist'].includes(profile)) { + if (!['dev', 'release', 'prod', 'perry-dev', 'dist'].includes(profile)) { throw new Error('Native require tests need a panic=abort runtime profile'); } const packages = [ @@ -58,7 +58,9 @@ export function prepareRequireRuntime(root) { } } const target = path.resolve(root, process.env.CARGO_TARGET_DIR ?? 'target'); - const runtime = prepared ? path.resolve(process.env.PERRY_RUNTIME_DIR) : path.join(target, profile); + // Cargo names the built-in `dev` profile's output directory `debug`. + const profileDir = profile === 'dev' ? 'debug' : profile; + const runtime = prepared ? path.resolve(process.env.PERRY_RUNTIME_DIR) : path.join(target, profileDir); // Refuse a misleading successful Cargo invocation (e.g. a cross-target // override) rather than falling back to an unrelated installed archive. for (const name of ['runtime', 'stdlib', 'ext_events', 'ext_http', 'ext_net', diff --git a/scripts/test-require-runtime.test.mjs b/scripts/test-require-runtime.test.mjs index 3df83cd615..35daa9abd3 100644 --- a/scripts/test-require-runtime.test.mjs +++ b/scripts/test-require-runtime.test.mjs @@ -54,7 +54,7 @@ test('prepared mode requires an explicit runtime directory', t => { assert.match(result.stderr, /needs an explicit PERRY_RUNTIME_DIR/); }); -test('unwind-enabled debug profiles remain rejected', t => { +test('debug is an output directory, not a Cargo profile', t => { const result = run(fixture(t), { PERRY_TEST_RUNTIME_PROFILE: 'debug' }); assert.notEqual(result.status, 0); assert.match(result.stderr, /panic=abort runtime profile/); diff --git a/scripts/test-string-static-spread.mjs b/scripts/test-string-static-spread.mjs index 9a0c902cbd..b6825633cb 100644 --- a/scripts/test-string-static-spread.mjs +++ b/scripts/test-string-static-spread.mjs @@ -7,7 +7,7 @@ import { fileURLToPath } from 'node:url'; import { spawnSync } from 'node:child_process'; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); -const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/perry-dev/perry'); +const compiler = process.env.PERRY_BIN ?? path.join(root, 'target/debug/perry'); const work = fs.mkdtempSync(path.join(os.tmpdir(), 'perry-string-static-spread-')); let passed = false; try { From fd5e62b32e59c9f657cd56c57a393c1fc62e023e Mon Sep 17 00:00:00 2001 From: jdalton Date: Mon, 5 Oct 2026 14:44:58 -0400 Subject: [PATCH 2/3] docs: add build profile changeset --- changelog.d/12056-build-profiles-ci-lanes.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelog.d/12056-build-profiles-ci-lanes.md diff --git a/changelog.d/12056-build-profiles-ci-lanes.md b/changelog.d/12056-build-profiles-ci-lanes.md new file mode 100644 index 0000000000..ec2b140a01 --- /dev/null +++ b/changelog.d/12056-build-profiles-ci-lanes.md @@ -0,0 +1,4 @@ +Perry now has a fast, debuggable `dev` profile and an optimized `prod` profile +that uses parallel code generation while retaining ThinLTO. Local build targets +and CI test lanes use the matching profiles, and the test guide now documents +fast, mid, and slow Rust suites with explicit timeboxes. From 24a1c4fcb8422fc76cb2b9ca74dfa4b8ce71dd6b Mon Sep 17 00:00:00 2001 From: jdalton Date: Mon, 5 Oct 2026 16:58:13 -0400 Subject: [PATCH 3/3] fix(build): align release artifacts with prod profile --- .github/workflows/release-packages.yml | 46 ++++++++++--------- crates/perry-ext-zlib/src/stream/driver.rs | 8 +++- crates/perry-runtime/src/buffer/view_tests.rs | 8 ++-- .../perry/src/commands/compile/well_known.rs | 5 +- 4 files changed, 39 insertions(+), 28 deletions(-) diff --git a/.github/workflows/release-packages.yml b/.github/workflows/release-packages.yml index 6b6a65e2bd..0b4c06c425 100644 --- a/.github/workflows/release-packages.yml +++ b/.github/workflows/release-packages.yml @@ -543,6 +543,10 @@ jobs: fi - name: Install Rust toolchain run: rustup toolchain install nightly-2026-10-04 --profile minimal --target x86_64-apple-darwin + - uses: ./.github/actions/perry-mbx-cache + with: + cache-generation: perry-release-x86_64-apple-darwin + save-on-workflow-dispatch: true - uses: ./.github/actions/setup-llvm22 # Keep the proven partial-failure cache for this exceptionally slow # Intel leg. mbx's object bundle is saved only after a successful job. @@ -870,8 +874,8 @@ jobs: # Keep old-sysroot objects isolated from the noble GTK4 build. Only # the outputs release packaging consumes cross that boundary. - src="target-glibc231/$TARGET/dist" - dst="target/$TARGET/dist" + src="target-glibc231/$TARGET/prod" + dst="target/$TARGET/prod" mkdir -p "$dst" for artifact in perry libperry_runtime.a libperry_runtime_abort.a libperry_runtime_core.a libperry_stdlib.a; do test -s "$src/$artifact" @@ -917,8 +921,8 @@ jobs: # Same boundary as the old-sysroot leg: only the artifacts packaging # consumes cross back into target/. - src="target-musl/$TARGET/dist" - dst="target/$TARGET/dist" + src="target-musl/$TARGET/prod" + dst="target/$TARGET/prod" mkdir -p "$dst" for artifact in perry libperry_runtime.a libperry_runtime_abort.a libperry_runtime_core.a libperry_stdlib.a; do test -s "$src/$artifact" @@ -1043,7 +1047,7 @@ jobs: shell: bash run: | set -euo pipefail - libs=$(find target -path "*/dist/libperry_runtime.a" -o -path "*/dist/perry_runtime.lib") + libs=$(find target -path "*/prod/libperry_runtime.a" -o -path "*/prod/perry_runtime.lib") if [ -z "$libs" ]; then echo "::error::no built runtime archives found under target/ — nothing to verify" exit 1 @@ -1055,11 +1059,11 @@ jobs: if: runner.os != 'Windows' run: | mkdir -p staging - cp target/${{ matrix.target }}/dist/perry staging/ + cp target/${{ matrix.target }}/prod/perry staging/ # Include static libraries for linking (runtime, stdlib, UI) for lib in libperry_runtime.a libperry_runtime_abort.a libperry_runtime_core.a libperry_stdlib.a libperry_ui_macos.a libperry_ui_gtk4.a; do - if [ -f "target/${{ matrix.target }}/dist/$lib" ]; then - cp "target/${{ matrix.target }}/dist/$lib" staging/ + if [ -f "target/${{ matrix.target }}/prod/$lib" ]; then + cp "target/${{ matrix.target }}/prod/$lib" staging/ fi done # #2532 — ship the perry-ext-* staticlibs so an out-of-tree install @@ -1067,7 +1071,7 @@ jobs: # drivers without the workspace source. `perry compile` finds them # via the same exe-dir / PERRY_LIB_DIR search as the runtime/stdlib # libs (optimized_libs.rs::resolve_prebuilt_ext_libs). - for lib in target/${{ matrix.target }}/dist/libperry_ext_*.a; do + for lib in target/${{ matrix.target }}/prod/libperry_ext_*.a; do [ -f "$lib" ] && cp "$lib" staging/ done # Closes #394: macOS legs also ship iOS-cross-compiled libs. @@ -1076,7 +1080,7 @@ jobs: # bottle's flat lib dir. library_search.rs's cross-compile # branch composes the right name based on --target. if [ "${{ runner.os }}" = "macOS" ]; then - dev_dir="target/aarch64-apple-ios/dist" + dev_dir="target/aarch64-apple-ios/prod" if [ -f "$dev_dir/libperry_runtime.a" ]; then cp "$dev_dir/libperry_runtime.a" "staging/libperry_runtime_ios.a" fi @@ -1086,7 +1090,7 @@ jobs: if [ -f "$dev_dir/libperry_ui_ios.a" ]; then cp "$dev_dir/libperry_ui_ios.a" "staging/libperry_ui_ios.a" fi - sim_dir="target/aarch64-apple-ios-sim/dist" + sim_dir="target/aarch64-apple-ios-sim/prod" if [ -f "$sim_dir/libperry_runtime.a" ]; then cp "$sim_dir/libperry_runtime.a" "staging/libperry_runtime_ios_sim.a" fi @@ -1129,7 +1133,7 @@ jobs: throw 'WINDOWS_CODE_SIGNING_PFX_BASE64 is configured but WINDOWS_CODE_SIGNING_PFX_PASSWORD is missing.' } - $binary = "target/${{ matrix.target }}/dist/perry.exe" + $binary = "target/${{ matrix.target }}/prod/perry.exe" $certificate = Join-Path $env:RUNNER_TEMP 'perry-code-signing.pfx' try { $certificateBytes = [Convert]::FromBase64String($env:WINDOWS_CODE_SIGNING_PFX_BASE64) @@ -1170,7 +1174,7 @@ jobs: shell: pwsh run: | $ErrorActionPreference = 'Stop' - $binary = "target/${{ matrix.target }}/dist/perry.exe" + $binary = "target/${{ matrix.target }}/prod/perry.exe" $llvmBin = Join-Path $env:LLVM_SYS_221_PREFIX 'bin' $llvmReadObj = Join-Path $llvmBin 'llvm-readobj.exe' $llvmRuntime = Join-Path $llvmBin 'LLVM-C.dll' @@ -1201,7 +1205,7 @@ jobs: # Include static libraries for linking (runtime, stdlib, UI) $libs = @("perry_runtime.lib", "perry_stdlib.lib", "perry_ui_windows.lib") foreach ($lib in $libs) { - $path = "target/${{ matrix.target }}/dist/$lib" + $path = "target/${{ matrix.target }}/prod/$lib" if (Test-Path $path) { Copy-Item $path staging/ } @@ -1225,7 +1229,7 @@ jobs: New-Item -ItemType Directory -Force -Path $androidLibDir | Out-Null $androidLibs = @("libperry_runtime.a", "libperry_stdlib.a", "libperry_ui_android.a") foreach ($lib in $androidLibs) { - $src = "target/aarch64-linux-android/dist/$lib" + $src = "target/aarch64-linux-android/prod/$lib" if (-not (Test-Path -LiteralPath $src -PathType Leaf)) { Write-Error "Required Android library missing from ${{ matrix.artifact }}: $src" exit 1 @@ -1292,7 +1296,7 @@ jobs: TAG="$RELEASE_TAG" ARCHIVE="${{ matrix.artifact }}.tar.gz" URL="https://github.com/${{ github.repository }}/releases/download/${TAG}/${ARCHIVE}" - "target/${{ matrix.target }}/dist/perry" updater sign-cli-manifest \ + "target/${{ matrix.target }}/prod/perry" updater sign-cli-manifest \ --artifact "$ARCHIVE" --platform "$ARCHIVE" --url "$URL" \ --release-version "${TAG#v}" --key-id "$PERRY_CLI_UPDATE_KEY_ID" \ --secret-key-b64 "$PERRY_CLI_UPDATE_SIGNING_KEY" > "$ARCHIVE.update.json" @@ -1313,7 +1317,7 @@ jobs: $tag = $env:RELEASE_TAG $archive = "${{ matrix.artifact }}.zip" $url = "https://github.com/${{ github.repository }}/releases/download/$tag/$archive" - & "target/${{ matrix.target }}/dist/perry.exe" updater sign-cli-manifest ` + & "target/${{ matrix.target }}/prod/perry.exe" updater sign-cli-manifest ` --artifact $archive --platform $archive --url $url ` --release-version $tag.TrimStart('v') --key-id $env:PERRY_CLI_UPDATE_KEY_ID ` --secret-key-b64 $env:PERRY_CLI_UPDATE_SIGNING_KEY | Out-File -Encoding utf8 "$archive.update.json" @@ -1568,9 +1572,9 @@ jobs: shell: bash run: | set -euo pipefail - lib="target/${{ matrix.target }}/dist/libperry_runtime.a" + lib="target/${{ matrix.target }}/prod/libperry_runtime.a" # Windows MSVC emits perry_runtime.lib (no `lib` prefix). - [ -f "$lib" ] || lib="target/${{ matrix.target }}/dist/perry_runtime.lib" + [ -f "$lib" ] || lib="target/${{ matrix.target }}/prod/perry_runtime.lib" ./scripts/check_runtime_symbols.sh "$lib" # --- Package + manifest ---------------------------------------------- @@ -1594,7 +1598,7 @@ jobs: mkdir -p "$STAGING" # Required runtime + stdlib (always present on a successful build). for lib in libperry_runtime.a libperry_stdlib.a; do - src="target/${TARGET}/dist/${lib}" + src="target/${TARGET}/prod/${lib}" if [ ! -f "$src" ]; then echo "::error::Expected $src after build but it's missing — aborting bundle." exit 1 @@ -1605,7 +1609,7 @@ jobs: # principle, but we built it above so this should exist; we hard-fail # if it's missing so the worker doesn't see a silently-degraded # bundle). - UI_SRC="target/${TARGET}/dist/${UI_LIB}" + UI_SRC="target/${TARGET}/prod/${UI_LIB}" if [ ! -f "$UI_SRC" ]; then echo "::error::UI lib $UI_SRC missing after build — aborting bundle." exit 1 diff --git a/crates/perry-ext-zlib/src/stream/driver.rs b/crates/perry-ext-zlib/src/stream/driver.rs index f814d9a2a6..fdecf24b80 100644 --- a/crates/perry-ext-zlib/src/stream/driver.rs +++ b/crates/perry-ext-zlib/src/stream/driver.rs @@ -121,7 +121,13 @@ impl Gzip { GzipStage::Header(header) => { // flate2 parses the optional fields/header CRC without // decoding a body when the output slice is empty. - header.read(&mut [])?; + let consumed = header.read(&mut [])?; + if consumed != 0 { + return Err(io::Error::new( + ErrorKind::InvalidData, + "gzip header decoder wrote bytes to an empty buffer", + )); + } let old = std::mem::replace(&mut self.stage, GzipStage::Done(Input::default())); if let GzipStage::Header(header) = old { self.stage = GzipStage::Body(Inflate::new(header.into_inner(), false)); diff --git a/crates/perry-runtime/src/buffer/view_tests.rs b/crates/perry-runtime/src/buffer/view_tests.rs index c4ad8c5809..c3c0899b35 100644 --- a/crates/perry-runtime/src/buffer/view_tests.rs +++ b/crates/perry-runtime/src/buffer/view_tests.rs @@ -261,17 +261,15 @@ fn entry_byte_proof_resolves_both_layouts_and_rejects_other_receivers() { let owner = js_uint8array_alloc(32); let sub = js_buffer_slice(owner, 7, 15); let resolve = header::js_u8_resolve_read_data; - assert_eq!(resolve(value(owner)), unsafe { buffer_data(owner) } - as usize); - assert_eq!(resolve(value(sub)), unsafe { buffer_data(owner).add(7) } - as usize); + assert_eq!(resolve(value(owner)), buffer_data(owner) as usize); + assert_eq!(resolve(value(sub)), unsafe { buffer_data(owner).add(7) } as usize); assert!(!header::test_u8_inline_cache_holds(sub as usize)); assert_eq!(resolve(17.0), 0); assert_eq!(resolve(f64::from_bits(crate::value::TAG_UNDEFINED)), 0); let raw_buffer = js_buffer_alloc(8, 0); mark_as_array_buffer(raw_buffer as usize); assert_eq!(resolve(value(raw_buffer)), 0); - let foreign = unsafe { header::buffer_alloc_foreign(buffer_data(owner) as *mut u8, 32) }; + let foreign = header::buffer_alloc_foreign(buffer_data(owner) as *mut u8, 32); mark_as_uint8array(foreign as usize); assert_eq!(resolve(value(foreign)), 0); let pointer = resolve(value(owner)); diff --git a/crates/perry/src/commands/compile/well_known.rs b/crates/perry/src/commands/compile/well_known.rs index 0031543e29..d516d2fbaf 100644 --- a/crates/perry/src/commands/compile/well_known.rs +++ b/crates/perry/src/commands/compile/well_known.rs @@ -663,7 +663,10 @@ mod tests { .expect("native ext release step remains present"); let command: String = step .lines() - .skip_while(|line| !line.trim_start().starts_with("cargo build ")) + .skip_while(|line| { + let command = line.trim_start(); + !command.starts_with("cargo build ") && !command.starts_with("mbx build ") + }) .take_while(|line| !line.contains("|| echo")) .collect::>() .join(" ");