From 11cd3a65735ba7f0ccb5b2fb928ff52b8b1f8a10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Sun, 27 Sep 2026 15:15:51 +0200 Subject: [PATCH 1/4] deps(regex): take perex 0.1.10 and record the work a failed run leaves perex 0.1.10's `Search::run` fails with `RunError { error, remaining_work, buffers }`. Both call sites in `perex_runtime.rs` now set the budget from the failed run's remaining work, where they used to keep the entry budget and under-count what the failed call spent. Nothing observes that today, since WORK is usize::MAX on these paths. This is the adaptation the perex release carrying PerryTS/perex#3 (the package-shaped repeat and class fast paths) needs. Taking that release is then a version bump. --- Cargo.lock | 4 +- Cargo.toml | 2 +- .../perry-runtime/src/regex/perex_runtime.rs | 40 ++++++++----------- 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a748b33e8a..63377d7d09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4776,9 +4776,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perex" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1473d470930ed48574515a25df34900f3af89c6fa422d903e019121312a9f13e" +checksum = "08b8d5b07f5154bba623cad4a9cbbc8add8b072363b6d457ca591b435a106550" [[package]] name = "perry" diff --git a/Cargo.toml b/Cargo.toml index e0e0fafe70..5115e9f44e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -381,7 +381,7 @@ regex = "1.12" aho-corasick = "1.1" memchr = "2" # The single regular-expression engine, through crates/perry-perex. -perex = "0.1.9" +perex = "0.1.10" # turnloop P0/P1: the per-agent event-loop wait driver and, since P1, Perry's # stream sockets (docs/turnloop/p0-report.md, crates/perry-runtime/src/turnloop_net). # 0.1.0-alpha.3 switched turnloop's own dependency requirements from exact pins diff --git a/crates/perry-runtime/src/regex/perex_runtime.rs b/crates/perry-runtime/src/regex/perex_runtime.rs index 9cafb56082..f2b8f9a6cf 100644 --- a/crates/perry-runtime/src/regex/perex_runtime.rs +++ b/crates/perry-runtime/src/regex/perex_runtime.rs @@ -422,18 +422,14 @@ fn find_near_lent<'mem, S: ImmutableSubject>( // Both views are acquired once for the quantum that decides nearly // every per-call search; a `Search` is built and moved only if this // one pauses or asks for more scratch. - // On an error that is not a capacity request -- WorkLimit, - // InvalidProgram, ChangedResources, Cancelled -- `run` returns Err and - // drops the scratch and the remaining budget, where `new` + `advance` - // left a Search to read `remaining_work()` from. So `*budget` keeps its - // entry value and under-counts what the failed call spent. WORK is - // usize::MAX on every path here, so nothing observes it today; if a - // finite execution budget is ever reintroduced (see #10164/#10165), - // this stops being free and wants the engine's failure arm to report - // remaining work. - let mut search = match Search::run(resources, start, near, scratch, *budget, quantum) - .map_err(search_error)? - { + // A failed run reports the work it left (perex 0.1.10), so the budget + // records what the failed call spent, as a failed search did. + let run = + Search::run(resources, start, near, scratch, *budget, quantum).map_err(|failed| { + *budget = Budget::new(failed.remaining_work); + search_error(failed.error) + })?; + let mut search = match run { Run::Finished(mut finished) => { *budget = Budget::new(finished.remaining_work()); let position = finished.position(); @@ -554,18 +550,14 @@ pub(crate) fn find_near<'mem, S: ImmutableSubject>( poll()?; let buffers = MatchBuffers::new(memory, size)?; - // On an error that is not a capacity request -- WorkLimit, - // InvalidProgram, ChangedResources, Cancelled -- `run` returns Err and - // drops the scratch and the remaining budget, where `new` + `advance` - // left a Search to read `remaining_work()` from. So `*budget` keeps its - // entry value and under-counts what the failed call spent. WORK is - // usize::MAX on every path here, so nothing observes it today; if a - // finite execution budget is ever reintroduced (see #10164/#10165), - // this stops being free and wants the engine's failure arm to report - // remaining work. - let mut search = match Search::run(&resources, start, near, buffers, *budget, quantum) - .map_err(search_error)? - { + // A failed run reports the work it left (perex 0.1.10), so the budget + // records what the failed call spent, as a failed search did. + let run = + Search::run(&resources, start, near, buffers, *budget, quantum).map_err(|failed| { + *budget = Budget::new(failed.remaining_work); + search_error(failed.error) + })?; + let mut search = match run { Run::Finished(mut finished) => { *budget = Budget::new(finished.remaining_work()); let position = finished.position(); From 19912967a6c7967ea831f26e46fb81d408c57d48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Sun, 27 Sep 2026 15:16:29 +0200 Subject: [PATCH 2/4] changelog: key perex 0.1.10 fragment to PR 11548 --- changelog.d/11548-perex-0110-run-error.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelog.d/11548-perex-0110-run-error.md diff --git a/changelog.d/11548-perex-0110-run-error.md b/changelog.d/11548-perex-0110-run-error.md new file mode 100644 index 0000000000..225857b2ab --- /dev/null +++ b/changelog.d/11548-perex-0110-run-error.md @@ -0,0 +1,3 @@ +### Changed + +- The regex engine moves from perex 0.1.9 to 0.1.10. When a search fails, its run now reports the work it had left, and Perry's search sites record that work instead of keeping the budget they started with. Nothing observable changes today. This prepares the adoption of the perex release that carries PerryTS/perex#3, which cuts the package-shaped regex costs: uuid's `validate` −65%, jws's `JWS_REGEX.test` −84%, jsonwebtoken/decode −52% and uuid/v4 −48% in instructions (#10166). From 1f532cfc7722cf53c886bd984aa0282c0d77e034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Mon, 28 Sep 2026 07:53:46 +0000 Subject: [PATCH 3/4] deps(regex): take perex 0.1.11 under a one-time publish-age override perex 0.1.11 carries PerryTS/perex#3: package-shaped repeats and classes leave the per-character phase loop. It has no public API change from 0.1.10, so this is a version bump. 0.1.11 was published 2026-09-27T21:13:35Z, inside the 7-day global-min-publish-age window. The owner approved a one-time override on 2026-09-28 for this version only. Cargo.lock was resolved once with CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow, and the Cargo.toml comment records the approval, the publish time, and the sha256 the lock pins (4cacad0d...98a8), checked against the crates.io API. The soak window and .cargo/config.toml are unchanged. The Next App Route provider lock moves from perex 0.1.9 to 0.1.11 as well. Re-resolving it also adds perry-abi, which the provider's runtime already depends on on main but its lock predated. --- Cargo.lock | 4 ++-- Cargo.toml | 15 ++++++++++++++- .../packages/next-app-route/provider/Cargo.lock | 9 +++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63377d7d09..ab30bfef1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4776,9 +4776,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perex" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08b8d5b07f5154bba623cad4a9cbbc8add8b072363b6d457ca591b435a106550" +checksum = "4cacad0d8fd77338345abb71e4f8372ce93bf0e9205d845940f8e789b3fc98a8" [[package]] name = "perry" diff --git a/Cargo.toml b/Cargo.toml index 5115e9f44e..c2feb89f08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -381,7 +381,20 @@ regex = "1.12" aho-corasick = "1.1" memchr = "2" # The single regular-expression engine, through crates/perry-perex. -perex = "0.1.10" +# 0.1.11 carries PerryTS/perex#3 (package-shaped repeats and classes leave the +# per-character phase loop; release commit 80845f5310, tag v0.1.11). It is +# younger than the 7-day `global-min-publish-age` soak (.cargo/config.toml), +# so Cargo.lock was resolved once with CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow +# under an owner-approved one-time publish-age override (2026-09-28), for this +# version only; the window itself is unchanged. No public API change from +# 0.1.10. Published 2026-09-27T21:13:35Z, sha256 +# 4cacad0d8fd77338345abb71e4f8372ce93bf0e9205d845940f8e789b3fc98a8 — the +# checksum Cargo.lock records, verified against +# https://crates.io/api/v1/crates/perex/0.1.11. As with turnloop above, the +# opt-out is a committed, reviewable change, never a silent one, and the lock +# pins the exact artifact. The override lapses on its own on 2026-10-04, when +# 0.1.11 clears the window. +perex = "0.1.11" # turnloop P0/P1: the per-agent event-loop wait driver and, since P1, Perry's # stream sockets (docs/turnloop/p0-report.md, crates/perry-runtime/src/turnloop_net). # 0.1.0-alpha.3 switched turnloop's own dependency requirements from exact pins diff --git a/tests/release/packages/next-app-route/provider/Cargo.lock b/tests/release/packages/next-app-route/provider/Cargo.lock index d07f754d08..018b77bbd6 100644 --- a/tests/release/packages/next-app-route/provider/Cargo.lock +++ b/tests/release/packages/next-app-route/provider/Cargo.lock @@ -2960,9 +2960,13 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perex" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1473d470930ed48574515a25df34900f3af89c6fa422d903e019121312a9f13e" +checksum = "4cacad0d8fd77338345abb71e4f8372ce93bf0e9205d845940f8e789b3fc98a8" + +[[package]] +name = "perry-abi" +version = "0.5.1654" [[package]] name = "perry-base64" @@ -3132,6 +3136,7 @@ dependencies = [ "node-semver", "notify", "perex", + "perry-abi", "perry-base64", "perry-diagnostics", "perry-dispatch", From 8803718ccdff2a2808a0124072551860f06c22d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Mon, 28 Sep 2026 10:58:54 +0000 Subject: [PATCH 4/4] changelog: perex 0.1.11 numbers and the publish-age override --- changelog.d/11548-perex-0110-run-error.md | 3 --- changelog.d/11548-perex-0111-package-regex-shapes.md | 5 +++++ 2 files changed, 5 insertions(+), 3 deletions(-) delete mode 100644 changelog.d/11548-perex-0110-run-error.md create mode 100644 changelog.d/11548-perex-0111-package-regex-shapes.md diff --git a/changelog.d/11548-perex-0110-run-error.md b/changelog.d/11548-perex-0110-run-error.md deleted file mode 100644 index 225857b2ab..0000000000 --- a/changelog.d/11548-perex-0110-run-error.md +++ /dev/null @@ -1,3 +0,0 @@ -### Changed - -- The regex engine moves from perex 0.1.9 to 0.1.10. When a search fails, its run now reports the work it had left, and Perry's search sites record that work instead of keeping the budget they started with. Nothing observable changes today. This prepares the adoption of the perex release that carries PerryTS/perex#3, which cuts the package-shaped regex costs: uuid's `validate` −65%, jws's `JWS_REGEX.test` −84%, jsonwebtoken/decode −52% and uuid/v4 −48% in instructions (#10166). diff --git a/changelog.d/11548-perex-0111-package-regex-shapes.md b/changelog.d/11548-perex-0111-package-regex-shapes.md new file mode 100644 index 0000000000..9318e4fedd --- /dev/null +++ b/changelog.d/11548-perex-0111-package-regex-shapes.md @@ -0,0 +1,5 @@ +### Performance + +- The regex engine moves from perex 0.1.9 to 0.1.11. 0.1.11 carries PerryTS/perex#3, which takes package-shaped repeats and character classes out of the matcher's per-character loop. Measured with `perf stat -e instructions:u` (two-N differential) on perrymaster against `main`: uuid's `validate` regex −65.2% per call, jws's `JWS_REGEX.test` −84.3%, `/^\d+$/.test` −5.4%, and on the package workloads jsonwebtoken/decode −61.1%, uuid/v4 −47.9%, uuid/v7 −34.4%, nanoid/generate −30.4% and uuid/v5_parse −28.4%. Every output is byte-identical to Node 26.5.1, and peak RSS does not move beyond run-to-run noise (#10166). +- perex 0.1.10's `Search::run` fails with `RunError { error, remaining_work, buffers }`. Perry's two search sites now record the work a failed run left instead of keeping the budget they started with. Nothing observes this today, because the budget is `usize::MAX` on these paths. +- perex 0.1.11 is younger than the 7-day cargo `min-publish-age` soak. The owner approved a one-time override for this version on 2026-09-28. `Cargo.lock` was resolved once with `CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow`, and the `Cargo.toml` comment records the approval, the publish time and the sha256 the lock pins, checked against the crates.io API. The soak window is unchanged.