Skip to content

chore: merge train 233 (v0.5.1612) - #10783

Merged
proggeramlug merged 8 commits into
mainfrom
train233r
Sep 20, 2026
Merged

proggeramlug merged 8 commits into
mainfrom
train233r

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Merge train 233 — two agent-produced branches plus one repair, released as v0.5.1612.

Contents

source Change
#10708 + #10712 refactor(stdlib): remove the lru-cache and commander native bindings — 59 files, +99/−4405
test(hir): derive the shimmed-npm-shim test cases from the live registry instead of naming packages
fix(release): drop two perry-stdlib features train 231 deleted from the next-app provider

Both PRs were CONFLICTING and are combined rather than rebased separately: they move the same absolute counts, so two independently-correct rebases would collide with each other. That collision is #10739.

Two main-side reds, both of them mine, both fixed here

perry-hir's remedy_is_scoped_to_bundled_npm_shims was stale. It asserted shimmed_package_module("dayjs.businessDaysAdd") == Some("dayjs"); train 231 removed the dayjs binding, so the lookup correctly returned None. Production code right, test wrong — and per-PR cargo-test scopes to the crates a diff affects, so the next perry-hir PR would have gone red for a reason it did not cause.

The fix derives the positive cases from the live registry (NATIVE_MODULES minus Node builtins minus Perry-owned surfaces) — 47 entries today, where two package names were hardcoded. A binding removal now shrinks that set instead of reddening the test. The negative half stays literal on purpose: those are categories (fs.bogus, a node: spelling, perry/gc.notReal, crypto.subtle.digest, an unshimmed package), no removal can delete them, and they are what fails if the derivation ever drifts loose. Both halves were sabotage-checked — forcing shimmed_package_module to always-None and to always-Some each fail the test, the second in its strong form (returning the correct module prefix, so only the literal negatives can catch it).

The release provider enabled two features that no longer exist. Train 231 deleted rate-limit and bundled-dayjs from crates/perry-stdlib/Cargo.toml; tests/release/packages/next-app-route/provider/stdlib/Cargo.toml still asked for both, so the provider no longer resolved. It is not a workspace member, so cargo check --workspace --all-targets is structurally blind to it and only the full tier's nightly release-package smoke sees it. The cheap standing check is comm -23 between the provider's feature list and perry-stdlib's defined features — worth running on every future removal.

The removals: why commander stays in despite losing four stderr lines

After removal, real commander 15.0.0 matches Node byte-for-byte on stdout — option defaults, --no- negation, .opts(), program.args, processedArgs, subcommand .argument()/.action() dispatch, variadics, helpInformation(), --help through configureOutput, and all four CommanderError codes under exitOverride(). But it prints nothing where Node prints error: unknown option '--nope' and three siblings. That is #10711.

It is not a regression, and the evidence is on main, not in a claim. crates/perry-ext-commander/src/lib.rs and crates/perry-stdlib/src/commander.rs at dd00a00305 contain zero matches for eprintln!|stderr|io::stderr — the native binding never wrote that text either. They also contain zero matches for exit_override|configure_output|help_information|processed_args, so the acceptance fixture could not even have run on main. stderr was empty before and is empty after; every value commander computes now matches Node where previously no CommanderError was thrown at all.

Correction to #10711's impact text while we are here: it says --help routed through the configuration object also loses its text. It does not — configureOutput({ writeOut }) + --help is byte-identical. Only the outputError(msg, writeErr) shape is affected, so the blast radius is narrower than the issue states.

lru-cache 11.5.2 is byte-identical outright, including the four things the native binding got wrong: instanceof, constructor.name, forEach, and dispose firing on eviction.

A conflict resolution that compiled and was wrong

#10708 removed the "LRUCache" => ("lru-cache","LRUCache") native-parent arm from class_decl.rs but missed the parallel copy in from_ast.rs, whose own comment says to keep the two in lockstep. With lower_lru_cache_subclass_init deleted from codegen, class X extends LRUCache in real compiled source would have routed to a path that no longer exists. There is a _ => None catch-all, so it compiles either way and no gate would have caught it. Removed here.

Two more of the same species: taking the removal PR's side on crates/perry-stdlib/Cargo.toml's full = [...] would have resurrected rate-limit, bundled-dotenv and bundled-dayjs, all deleted by train 231; and dropping the marked region of well_known_bindings.toml orphaned a trailing date = ..., producing a duplicate key that no compile can see because the file is read at runtime.

Counts re-derived on this tree, not carried

script result
workspace_architecture.py --check --print-summary 70 members, externalize=21, keep=44 — policy: OK
native_result_ledger.py 356 rows / 307 providers
unrooted_local_shape.py --check 555 — OK
string_payload_access_inventory.py 406 inline / 14 helpers — unchanged
binding_governance.py --check 28 ext crates — OK
binding_pins.mjs --check 24 pinned, lock-step holds

Cargo.lock regenerated with cargo metadata --offline: exactly 32 lines, exactly lru, perry-ext-commander, perry-ext-lru-cache, nothing else.

Validation

Assembled on dd00a00305; both source branches asserted fresh; no attribution trailers. Nine cheap gates, cargo check --workspace --all-targets under -D warnings, all five pinned artifacts byte-identical before and after the sweep, and seven unit suites with an empty failing set — the first train where that gate has a baseline of zero.

lint completed its full 6-of-6 compile tier with nothing outside the known-red public-baseline step.

Gap sweep at PERRY_RUN_TIMEOUT=30, seven areas aimed at what a binding removal can break — heritage, module resolution, and the class X extends path the from_ast.rs fix touches — every area asserted live, zero unexplained regressions:

class 83   import 20   module 14   cache 14   extends 8   require 5   cli 1

Two integration suites report rc=101. Both are cargo refusing a target this train deletes (package ID specification 'perry-ext-lru-cache' did not match any packages, and the deleted issue_10293_lru_cache_subclass.rs), not test failures — the surviving edited suite, issue_10439_native_binding_import_provenance, passes. The landing gate now requires proof of both halves before accepting such a code: the log must show cargo could not find the target and git diff --name-status must show this train deletes it.

Ralph Küpper added 8 commits September 20, 2026 06:11
`remedy_is_scoped_to_bundled_npm_shims` asserted
`shimmed_package_module("dayjs.businessDaysAdd") == Some("dayjs")`, but
v0.5.1610 removed the `dayjs` native binding (with `qs`, `fastify`,
`date-fns`, `rate-limiter-flexible` and `node-cron`), so the classifier
correctly answers `None`. The production code is right; the test had
outlived its subject and was reddening `main`.

Swapping in another package name would re-arm the same trap for the next
removal (`lru-cache`, `commander`, `pg`, `mysql2`, `decimal.js` are
queued), so the positive cases now derive from `NATIVE_MODULES`: a helper
filters it to the entries that are neither Node builtins nor Perry-owned
surfaces and the test asserts every one resolves and names itself in the
remedy. The sibling end-to-end test carried the same trap on `lodash` and
is derived the same way.

The negative half stays literal — those are categories, not packages, and
each pins a distinct branch of `shimmed_package_module`. Verified the test
still fails in both directions by stubbing the function to return `None`
unconditionally and to return `Some` unconditionally.
Fixes #10685 -- the removal is the fix. Native `instanceof` threw
"Right-hand side of 'instanceof' is not callable" and constructor.name was
undefined (the handle isn't a real class object); core get/set/eviction
logic was otherwise correct, but forEach/dispose silently no-op'd where
npm's real implementation visits/invokes.

Removes both copies (crates/perry-ext-lru-cache/ and the feature-gated
crates/perry-stdlib/src/lru_cache.rs), the dedicated #10293 native-subclass
machinery (crates/perry-runtime/src/lru_subclass.rs plus its call sites in
perry-codegen), the LRUCache-only arms in every shared HIR/codegen
recognition point (LRUCache/Command/Big/Decimal/BigNumber share several
match blocks; only LRUCache's line is touched here), and every registry
row (well_known_bindings.toml, NATIVE_MODULES, the API manifest,
stdlib_features.rs, native_result_ledger, workspace-architecture.json,
ci_ext_link_scope.py, Android stubs).

Based on PR #10699's branch (fix/10439-native-binding-import-provenance):
without that fix, lru-cache at its default import name is unreachable
regardless of perry.compilePackages, so this removal is not independently
mergeable.
Fixes #10686 -- the removal is the fix. Native program.args was undefined;
boolean option defaults serialized as the truthy string "false"; subcommand
.action() callbacks never fired; missing-required-argument and
unknown-option validation (Node's commander.missingArgument /
commander.unknownOption) was entirely absent.

Removes both copies (crates/perry-ext-commander/ and the feature-gated
crates/perry-stdlib/src/commander.rs, including its registered GC-root
scanner), the Command-only arms in every shared HIR/codegen recognition
point (LRUCache/Command/Big/Decimal/BigNumber share several match blocks;
only Command's line is touched here, including the dedicated
is_commander/is_commander_method fluent-chain continuation in
static_and_instance.rs), and every registry row (well_known_bindings.toml,
NATIVE_MODULES, the API manifest, stdlib_features.rs, native_result_ledger,
gc_runtime_root_holders.json, workspace-architecture.json, Android stubs).

commander's real npm source subclasses node:events' EventEmitter directly
(class Command extends EventEmitter) -- Perry's existing generic
EventEmitter-subclass support already handles that once compiled from
source, so no dedicated native-subclass machinery was needed here (unlike

bundled-commander is referenced only by perry-stdlib's `full` feature
umbrella (checked every other umbrella in Cargo.toml); no other umbrella
needs retargeting by this or the sibling decimal.js/lru-cache removals.

Based on PR #10699's branch (fix/10439-native-binding-import-provenance):
without that fix, commander at its default import name is unreachable
regardless of perry.compilePackages, so this removal is not independently
mergeable.
Both removals record absolute baselines that main has moved past and that
collide with each other (#10739), so none of them may be hand-merged. Each
number below was produced by re-running the script that owns the file on
THIS tree, not by arithmetic from either PR's recorded figure:

  workspace-architecture.json   members 72 -> 70, externalize 23 -> 21
                                (python3 scripts/workspace_architecture.py
                                 --check --print-summary)
  scripts/native_result_ledger.py  rows 369 -> 356, providers 320 -> 307
                                (python3 scripts/native_result_ledger.py;
                                 369 -> 367 -> 356 across the two removals)
  unrooted_local_shape_baseline    total 562 -> 555
                                (python3 scripts/unrooted_local_shape.py
                                 --update-baseline)
  docs/src/api/reference.md        2923/126 -> 2903/124
  docs/api/perry.d.ts              2043/124 -> 2041/122
                                (scripts/regen_api_docs.sh)
  Cargo.lock                    regenerated with `cargo metadata --offline`
                                (drops lru, perry-ext-commander,
                                 perry-ext-lru-cache and nothing else)

Also in this commit:

- crates/perry-hir/src/lower_decl/class_decl/from_ast.rs: drop the #10293
  `"LRUCache" => ("lru-cache", "LRUCache")` native-parent arm. #10708 removed
  only the copy in class_decl.rs; from_ast.rs holds the parallel arm its own
  comment says to keep in lockstep, and codegen's
  `lower_lru_cache_subclass_init` is gone, so a `class X extends LRUCache`
  from the real compiled source would have been routed to a path that no
  longer exists.
- crates/perry/well_known_bindings.toml: drop the `date` line orphaned by the
  commander entry's removal (it made the file fail to parse as TOML).
- crates/perry/src/commands/compile/host_config.rs: the #5137 wildcard-skip
  comment named commander/dayjs/lru-cache and `js_commander_new`, all of
  which are now deleted; re-point it at ioredis/`js_ioredis_new`.
- changelog.d fragments: record each package's acceptance result against the
  real npm package and the pinned Node oracle.
@proggeramlug
proggeramlug merged commit 1698e7f into main Sep 20, 2026
22 of 24 checks passed
@proggeramlug
proggeramlug deleted the train233r branch September 20, 2026 05:20
@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: 9604ca1c-aa68-4ab3-96cd-313d856d3bb1

📥 Commits

Reviewing files that changed from the base of the PR and between dd00a00 and 2d4c9f3.

⛔ 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 (61)
  • CLAUDE.md
  • Cargo.toml
  • changelog.d/10708-remove-lrucache-binding.md
  • changelog.d/10712-remove-commander-binding.md
  • changelog.d/10779-hir-shimmed-package-test.md
  • changelog.d/10781-release-provider-stale-features.md
  • crates/perry-api-manifest/src/entries.rs
  • crates/perry-api-manifest/src/entries/part_1.rs
  • crates/perry-codegen/src/expr/mod.rs
  • crates/perry-codegen/src/expr/this_super_call.rs
  • crates/perry-codegen/src/expr/write_barrier.rs
  • crates/perry-codegen/src/lower_call/builtin.rs
  • crates/perry-codegen/src/lower_call/native_table/node_misc.rs
  • crates/perry-codegen/src/lower_call/new_helpers.rs
  • crates/perry-codegen/src/runtime_decls/stdlib_ffi.rs
  • crates/perry-codegen/src/runtime_decls/stdlib_ffi/utilities.rs
  • crates/perry-codegen/src/runtime_decls/stdlib_ffi_part2.rs
  • crates/perry-ext-commander/Cargo.toml
  • crates/perry-ext-commander/src/lib.rs
  • crates/perry-ext-lru-cache/Cargo.toml
  • crates/perry-ext-lru-cache/src/lib.rs
  • crates/perry-ext-lru-cache/src/tests.rs
  • crates/perry-ext-lru-cache/tests/gc_survival.rs
  • crates/perry-hir/src/destructuring/var_decl/native_fetch.rs
  • crates/perry-hir/src/destructuring/var_decl/native_new.rs
  • crates/perry-hir/src/destructuring/var_decl_sources.rs
  • crates/perry-hir/src/eval_classifier.rs
  • crates/perry-hir/src/js_transform/imports.rs
  • crates/perry-hir/src/lower/expr_call/static_and_instance.rs
  • crates/perry-hir/src/lower/expr_member/native_dispatch.rs
  • crates/perry-hir/src/lower/module_decl.rs
  • crates/perry-hir/src/lower/tests.rs
  • crates/perry-hir/src/lower_decl/class_decl.rs
  • crates/perry-hir/src/lower_decl/class_decl/from_ast.rs
  • crates/perry-hir/src/lower_patterns.rs
  • crates/perry-runtime/src/lib.rs
  • crates/perry-runtime/src/lru_subclass.rs
  • crates/perry-stdlib/Cargo.toml
  • crates/perry-stdlib/src/commander.rs
  • crates/perry-stdlib/src/lib.rs
  • crates/perry-stdlib/src/lru_cache.rs
  • crates/perry-ui-android/src/stdlib_stubs.rs
  • crates/perry/src/commands/compile/collect_modules/feature_detect.rs
  • crates/perry/src/commands/compile/host_config.rs
  • crates/perry/src/commands/compile/well_known.rs
  • crates/perry/src/commands/stdlib_features.rs
  • crates/perry/tests/issue_10293_lru_cache_subclass.rs
  • crates/perry/tests/issue_10439_native_binding_import_provenance.rs
  • crates/perry/well_known_bindings.toml
  • docs/api/perry.d.ts
  • docs/examples/stdlib/other/snippets.ts
  • docs/src/api/reference.md
  • docs/src/native-libraries/governance.md
  • docs/src/stdlib/other.md
  • docs/src/stdlib/overview.md
  • scripts/ci_ext_link_scope.py
  • scripts/gc_runtime_root_holders.json
  • scripts/native_result_ledger.py
  • scripts/unrooted_local_shape_baseline.json
  • tests/release/packages/next-app-route/provider/stdlib/Cargo.toml
  • workspace-architecture.json
 _____________________________________________________________________________________________________
< Care about your craft. Why spend your life developing software unless you care about doing it well? >
 -----------------------------------------------------------------------------------------------------
  \
   \   \
        \ /\
        ( )
      .( 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.

1 participant