Skip to content

chore: merge train 240 (v0.5.1619) - #10819

Merged
proggeramlug merged 5 commits into
mainfrom
train240r
Sep 20, 2026
Merged

proggeramlug merged 5 commits into
mainfrom
train240r

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Merge train 240 — four more binding removals, released as v0.5.1619.

Contents

PR Change
#10795 refactor(stdlib): remove the cron, exponential-backoff, moment and node-forge native bindings — 58 files, +76 / −6,810

Plus two fixes the train adds, both found while reviewing it.

The PR is built the right way round

Phase 1 probed nine packages at their pinned upstream versions — cheerio, cron, exponential-backoff, ioredis, moment, node-forge, nodemailer, undici, ws — forcing real-source compilation and diffing stdout byte-for-byte against node --experimental-strip-types. Phase 2 removes only the four that passed, with a concrete blocker recorded for each of the five that stay.

That ordering is the direct lesson of #10765, where typescript had to be pulled at the last minute because removing its binding made perry execute real typescript.js for the first time and it threw (#10772). Probing before diffing is how that gets caught.

The fixtures also show attention to reproducibility rather than to getting a green: cron asserts guaranteed count bounds rather than an exact tick count, because the phase offset within the first wall-clock second is not reproducible across two process launches; moment never calls moment() with no arguments; node-forge asserts derived facts — bit length, round-trip equality, verify result — rather than diffing raw RSA bytes.

Two defects found in review, fixed here

1. The release provider broke again, in exactly the way it broke nine trains ago. tests/release/packages/next-app-route/provider/stdlib/Cargo.toml still enabled bundled-moment and bundled-exponential-backoff, which this PR deletes from perry-stdlib. That crate is not a workspace member, so cargo check --workspace --all-targets — the gate that would normally catch an undefined feature — is structurally blind to it; it breaks only in the nightly release-package smoke.

Merge train 231 did the same thing with rate-limit and bundled-dayjs. Second occurrence in one day, with five more removals queued, so it is now checked rather than remembered: check_nonworkspace_features.py derives perry-stdlib's defined features and every non-workspace consumer's requested ones and refuses the difference. Proven to discriminate — clean on the fixed tree, exits 1 on the pre-fix tree naming both features. It runs as a cheap gate, before the build.

2. The PR deleted test_gap_cron_cronjob.ts; this train keeps it. After the binding is gone, import { CronJob } from "cron" resolves to the real npm package — still a devDependency at ^4.4.0 — so the fixture stops testing a Rust shim and starts witnessing the thing the removal claims works. That is the precedent train 231 set by retaining test_gap_dayjs_factory_arg and test_gap_ratelimiter_memory.

It is also a fixture worth not discarding. #10581 rewrote its wait as a barrier rather than a deadline after the original raced a fixed 10-second wall clock against a one-per-second schedule and printed false when the clock won — read as a miscompile on a loaded runner, when PERRY_RUN_TIMEOUT is itself 10s. Its header records why no fallback bound is permitted: any bound that prints, throws or exits differently on expiry reintroduces the same defect at a different threshold. None of that survives deleting the file.

It passesgap_cron ran=1 rc=0 against real cron 4.4.0.

Counts re-derived on this tree

script result
workspace_architecture.py --check policy: OK
native_result_ledger.py 349 rows / 300 providers
unrooted_local_shape.py --check OK
binding_governance.py --check 24 extension crates
binding_pins.mjs --check 20 pinned, lock-step holds

Cargo.lock regenerated with cargo metadata --offline; all four perry-ext-{cron,exponential-backoff,moment,node-forge} crates confirmed absent. perry-ext-cron disappearing completes what train 231 started — it removed node-cron but deliberately kept cron, since the two shared that crate.

Validation

Assembled on b9ba951ff8; source head asserted fresh; no attribution trailers. Ten cheap gates (the new one included), cargo check --workspace --all-targets under -D warnings, all five pinned artifacts byte-identical before and after, seven unit suites with an empty failing set, and lint complete at 6-of-6 with nothing outside the known-red public-baseline step.

Both sweep-tier gates this driver gained today are green on their own terms: cor_native-region-proof and cor_native-abi-proof at failed_workloads=[], and repsel_census rc=0 wasted_promotion=False.

The integration-suite derivation correctly separated one surviving suite from two the train deletes — live=[('perry-api-manifest','stub_inventory')] deleted=[('perry-ext-node-forge','openssl_e2e'), ('perry-hir','node_forge_namespace_lowering')] — rather than reporting the deletions as failures, which is what it did before train 234 fixed it.

Gap sweep at PERRY_RUN_TIMEOUT=30, seven areas, every one asserted live, zero unexplained regressions:

class 83   import 20   date 16   module 14   crypto 7   require 5   cron 1

Run under a load average that peaked above 200 from concurrent builds, so any single failure would have been re-run standalone before being believed. There were none.

perry-bot and others added 5 commits September 20, 2026 13:39
…ative bindings

Removes the perry-ext-cron, perry-ext-exponential-backoff, perry-ext-moment,
and perry-ext-node-forge crates (and each package's hidden perry-stdlib-side
duplicate: cron.rs, exponential_backoff.rs, moment.rs), plus their
well_known_bindings.toml rows, NATIVE_MODULE_TABLE dispatch rows, HIR
special-casing, FFI declarations, and API-manifest entries.

Real npm source for all four now compiles cleanly via perry.compilePackages
and matches node --experimental-strip-types byte-for-byte on a fixture
exercising each package's primary documented use:
  - cron 4.4.0: CronJob tick scheduling + CronTime pattern parsing (2 modules)
  - exponential-backoff 3.1.3: backOff retry/backoff/predicate paths (1 module)
  - moment 2.30.1: parse/format/arithmetic/diff/duration (1 module)
  - node-forge 1.4.0: RSA keygen + X.509 build/sign/verify + PEM round-trip
    (1 module)

cron's two event-loop liveness FFI symbols (js_cron_timer_tick /
js_cron_timer_has_pending) stay as unconditional 0-returning stubs -- the
generated entry loop calls them every iteration regardless of whether a
program uses cron at all.

Five other probed packages in the same 9-package batch are NOT removed:

  - cheerio 1.2.0: cheerio.load() returns a callable object decorated with
    static/prototype properties (Object.assign(initialize, staticMethods,
    {...})); calling it as a function ($('h2')) throws
    'TypeError: string "h2" is not a function' under Perry, even though
    'typeof $' correctly reports "function". Real compiler defect, not
    attempted here.

  - ioredis 5.11.1: functionally correct (stdout byte-for-byte identical to
    node; two Perry-only stderr warnings about a circular '.default'
    access that node's loader doesn't hit for the same import -- benign,
    stdout-only comparison is this repo's convention). NOT removed: the
    literal string "ioredis" is shared infrastructure, not just an npm
    package name. It is (a) the well_known_bindings.toml lookup key that
    EXT_PREFIX_REGISTRY's 'js_ioredis_*' prefix resolves through for
    iovalkey and redis's own static-lib auto-linking (see
    perry-codegen/src/ext_registry.rs's own comment: "ioredis, iovalkey,
    and valkey all share this wrapper... so the single 'ioredis' binding
    key covers every RESP package"), and (b) the internal canonical
    dispatch key that iovalkey/redis's bare 'Redis' type-name resolution
    routes through in 8 HIR/codegen files (static_and_instance.rs,
    native_new.rs, module_decl.rs, local_natives.rs, misc.rs, fn_decl.rs,
    expr_function.rs, ir/module.rs). Deregistering it would break iovalkey
    and redis, which are staying.

  - nodemailer 9.0.3: confirms the known #10649 gap -- nodemailer's
    lib/xoauth2/index.js does 'class XOAuth2 extends Stream' against the
    BARE node:stream Stream (not Readable/Writable/Duplex/Transform, which
    #10649 fixed). 'new XOAuth2(...)' throws 'TypeError: is not a
    constructor'. This is loaded unconditionally on require("nodemailer")
    (nodemailer.js -> smtp-transport -> xoauth2), so any OAuth2 SMTP auth
    (e.g. Gmail) is broken under a real-source compile, even though the
    narrower JSONTransport/sendMail smoke path compiles and runs correctly.

  - undici 8.9.0: real source compiles (112 modules) but request() throws
    "TypeError: Cannot read properties of undefined (reading 'length')"
    before attempting a TCP connect -- minimal repro:
    import { request } from "undici"; await request("http://127.0.0.1:1/x")

  - ws 8.21.1: real source compiles and completes the WebSocket handshake
    correctly (verified byte-for-byte against a raw curl Upgrade request,
    matching RFC 6455's example Sec-WebSocket-Accept), but the compiled
    WebSocketServer then throws "TypeError: Cannot read properties of
    undefined (reading 'destroy')" immediately after the handshake, before
    the user-level 'connection' event ever fires.

Counts re-derived from the resolved tree, not carried forward: workspace
members / API-manifest NATIVE_MODULES / crates all agree at 66;
scripts/native_result_ledger.py: 356->349 rows, 307->300 providers;
scripts/unrooted_local_shape.py --update-baseline; docs/api/perry.d.ts and
docs/src/api/reference.md regenerated from a fresh release build
(2041->2026 entries, 122->118 modules); docs/src/native-libraries/governance.md
regenerated via binding_governance.py --table.

Not run: the compile tier of run_lint_gates.sh (known-red on this Linux
host per CLAUDE.md); a full gap sweep (fixed port, not available on this
shared host). run_lint_gates.sh with SKIP_COMPILE_GATES=1: 78 of 79 passed,
1 pre-existing failure (Public benchmark evidence freshness, #10707/#10573,
unrelated to this change).
@proggeramlug
proggeramlug merged commit c1d9f73 into main Sep 20, 2026
23 of 25 checks passed
@proggeramlug
proggeramlug deleted the train240r branch September 20, 2026 13:53
@coderabbitai

coderabbitai Bot commented Sep 20, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: f3ebf226-6054-4420-afcd-2f6aebc58a53

📥 Commits

Reviewing files that changed from the base of the PR and between b9ba951 and 869091b.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • scripts/native_result_ledger.tsv is excluded by !**/*.tsv
📒 Files selected for processing (60)
  • CLAUDE.md
  • Cargo.toml
  • changelog.d/10795-keep-cron-gap-fixture.md
  • changelog.d/10795-release-provider-features.md
  • changelog.d/10795-remove-cron-backoff-moment-forge.md
  • crates/perry-api-manifest/src/entries.rs
  • crates/perry-api-manifest/src/entries/part_1.rs
  • crates/perry-api-manifest/src/entries/part_2.rs
  • crates/perry-api-manifest/tests/stub_inventory.rs
  • crates/perry-codegen/src/ext_registry.rs
  • crates/perry-codegen/src/lower_call/builtin.rs
  • crates/perry-codegen/src/lower_call/native_table/dates.rs
  • crates/perry-codegen/src/lower_call/native_table/media.rs
  • crates/perry-codegen/src/lower_call/native_table/mod.rs
  • crates/perry-codegen/src/lower_call/native_table/utils_crypto.rs
  • crates/perry-codegen/src/runtime_decls/stdlib_ffi/third_party.rs
  • crates/perry-codegen/src/runtime_decls/stdlib_ffi/utilities.rs
  • crates/perry-ext-cron/Cargo.toml
  • crates/perry-ext-cron/src/lib.rs
  • crates/perry-ext-exponential-backoff/Cargo.toml
  • crates/perry-ext-exponential-backoff/src/lib.rs
  • crates/perry-ext-moment/Cargo.toml
  • crates/perry-ext-moment/src/lib.rs
  • crates/perry-ext-node-forge/Cargo.toml
  • crates/perry-ext-node-forge/src/crypto.rs
  • crates/perry-ext-node-forge/src/lib.rs
  • crates/perry-ext-node-forge/tests/openssl_e2e.rs
  • crates/perry-hir/src/destructuring/var_decl/native_new.rs
  • crates/perry-hir/src/js_transform/local_natives.rs
  • crates/perry-hir/src/lower/expr_call/mod.rs
  • crates/perry-hir/src/lower/expr_call/native_module.rs
  • crates/perry-hir/src/lower/expr_call/static_and_instance.rs
  • crates/perry-hir/src/lower/module_decl.rs
  • crates/perry-hir/tests/node_forge_namespace_lowering.rs
  • crates/perry-stdlib/Cargo.toml
  • crates/perry-stdlib/src/cron.rs
  • crates/perry-stdlib/src/exponential_backoff.rs
  • crates/perry-stdlib/src/lib.rs
  • crates/perry-stdlib/src/moment.rs
  • crates/perry-ui-android/src/stdlib_stubs.rs
  • crates/perry/src/commands/compile/optimized_libs/tests.rs
  • crates/perry/src/commands/compile/well_known.rs
  • crates/perry/src/commands/stdlib_features.rs
  • crates/perry/well_known_bindings.toml
  • docs/api/perry.d.ts
  • docs/src/api/reference.md
  • docs/src/native-libraries/governance.md
  • docs/src/stdlib/other.md
  • docs/src/stdlib/utilities.md
  • scripts/ci_ext_link_scope.py
  • scripts/gc_runtime_root_holders.json
  • scripts/native_result_ledger.py
  • scripts/string_payload_access_baseline.txt
  • scripts/unrooted_local_shape_baseline.json
  • test-files/test_gap_backoff_options.ts
  • test-files/test_gap_moment_methods.ts
  • test-files/test_parity_moment.ts
  • test-parity/known_failures.json
  • tests/release/packages/next-app-route/provider/stdlib/Cargo.toml
  • workspace-architecture.json
 ___________________________________________________________________
< Your commit message says 'quick fix'. That's how folklore starts. >
 -------------------------------------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants