chore: merge train 240 (v0.5.1619) - #10819
Merged
Merged
Conversation
…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).
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (60)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merge train 240 — four more binding removals, released as v0.5.1619.
Contents
refactor(stdlib): remove thecron,exponential-backoff,momentandnode-forgenative bindings — 58 files, +76 / −6,810Plus 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 againstnode --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
typescripthad to be pulled at the last minute because removing its binding made perry execute realtypescript.jsfor 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:
cronasserts 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;momentnever callsmoment()with no arguments;node-forgeasserts 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.tomlstill enabledbundled-momentandbundled-exponential-backoff, which this PR deletes fromperry-stdlib. That crate is not a workspace member, socargo 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-limitandbundled-dayjs. Second occurrence in one day, with five more removals queued, so it is now checked rather than remembered:check_nonworkspace_features.pyderives 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 retainingtest_gap_dayjs_factory_argandtest_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
falsewhen the clock won — read as a miscompile on a loaded runner, whenPERRY_RUN_TIMEOUTis 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 passes —
gap_cron ran=1 rc=0against realcron4.4.0.Counts re-derived on this tree
workspace_architecture.py --checkpolicy: OKnative_result_ledger.pyunrooted_local_shape.py --checkOKbinding_governance.py --checkbinding_pins.mjs --checkCargo.lockregenerated withcargo metadata --offline; all fourperry-ext-{cron,exponential-backoff,moment,node-forge}crates confirmed absent.perry-ext-crondisappearing completes what train 231 started — it removednode-cronbut deliberately keptcron, 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-targetsunder-D warnings, all five pinned artifacts byte-identical before and after, seven unit suites with an empty failing set, andlintcomplete 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-proofandcor_native-abi-proofatfailed_workloads=[], andrepsel_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: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.