Skip to content

chore: merge train 225 (v0.5.1604) - #10748

Merged
proggeramlug merged 5 commits into
mainfrom
train225r
Sep 19, 2026
Merged

proggeramlug merged 5 commits into
mainfrom
train225r

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Merge train 225 — two PRs validated together as one tree, released as v0.5.1604.

Trains land as their own PR, so the source PRs are closed, not merged, and their close-keywords never fire. Issues resolved are listed at the bottom.

Contents

PR Change
#10740 tooling: classify the four unclassified net.Socket providers in the native result ledger
#10701 refactor(stdlib): remove the uuid native binding, compile the real package from source

#10740 fixes a gate that was red on main for four releases — and was hiding a real defect

scripts/native_result_ledger.py failed on pristine main with expected 371 classified rows, found 376. Attributed by counting rows per file at 4715bc2fa1 (green) against 91c6a05012 (first red): only native_table/net_events.rs moved, 53 → 58, from #10658's net.Socket surface cluster in merge train 221.

It went unnoticed because the workflow is path-filtered to the ledger's own two files, so drift originating anywhere else never triggers it — it fires on the next PR that happens to edit the ledger.

The stale constant was load-bearing as a mask. The row-count check runs first and raises, so the classification-coverage check never executed — and behind it sat four providers with no classification at all: js_ext_net_socket_on, js_net_socket_prepend_listener, js_net_socket_prepend_once_listener, js_net_socket_unpipe. Bumping the constant alone would have turned the gate green and shipped the real bug, since an unclassified result_kind misrepresents to the GC what a native call returns.

All four were classified by reading each provider's actual return type rather than by name. Every one returns its handle: i64 argument unchanged — a key into statics::sockets(), not a heap address — so NR_HANDLE_ID. Constants move to 376 rows / 326 providers.

Proven still able to fail, three ways: deleting a TSV row reports the count; deleting it and lowering EXPECTED_PROVIDERS reaches the coverage check and names the symbol; misclassifying one as NR_GCPTR is caught as a mismatch.

Count files re-derived, not hand-merged

Both of #10701's conflicts were absolute-count files, which auto-merge cleanly while being wrong — the mechanism described in #10739. Resolved by re-derivation against the assembled tree:

  • Cargo.lock regenerated from the resolved manifest: no perry-ext-uuid entries, no stale versions, cargo metadata accepting the tree.
  • scripts/unrooted_local_shape_baseline.json re-derived with the detector now on main: 580 → 578, because removing the uuid binding drops two findings. --check agrees at rc=0.

Validation

Assembled on d4ef732ab9; source heads asserted unchanged; both PRs proven fully represented by patch-id and by subject+author. All nine cheap gates, cargo check --workspace --all-targets under -D warnings, the release build of all five pinned artifacts, every unit suite, and a 5-area gap sweep with zero unexplained regressions and every area asserted to have run a non-zero number of tests. lint completed its full 6-of-6 compile tier with nothing outside the known-red public-baseline step.

Issues resolved

Closes #10738

Ralph Küpper added 5 commits September 19, 2026 18:06
…r gate

`scripts/native_result_ledger.py` is red on pristine `main`, blocking the
path-filtered `Native Result Ledger / check` workflow on every PR that
touches `native_table/**` or the ledger itself.

Two independent defects, one hiding the other.

1. Stale row count (bookkeeping). #10658's `net.Socket` surface cluster
   landed in merge train 221 and grew
   `native_table/net_events.rs` from 53 to 58 typed rows. `EXPECTED_ROWS`
   stayed at 371, so the gate failed with
   `expected 371 classified rows, found 376`.

2. Four unclassified providers (the real defect). Those five new rows
   carry four runtime symbols that were never added to
   `native_result_ledger.tsv`, so the table declared a result class the
   provider inventory had no opinion about. An unclassified `result_kind`
   misrepresents to the GC what a native call returns.

The count check runs FIRST and raises, so the classification-coverage
check never executed: the stale constant was acting as a mask. Bumping
the constant alone would have turned the gate green and shipped (2).

Each of the four providers was read, not name-matched. All four return
their `handle: i64` argument unchanged -- a `next_id_or_throw()` registry
id and key into `statics::sockets()`, not a heap address -- which is
exactly `NativeRetKind::HandleId` ("an integer registry id or provider
sentinel"):

  js_ext_net_socket_on                 perry-ext-net/src/handle_exports.rs:65
  js_net_socket_prepend_listener       perry-ext-net/src/lifecycle.rs:1040
  js_net_socket_prepend_once_listener  perry-ext-net/src/lifecycle.rs:1060
  js_net_socket_unpipe                 perry-ext-net/src/pipe.rs:325

`js_ext_net_socket_on` backs two rows (`on` and `addListener` share the
symbol), hence five rows from four symbols. The sibling
`js_net_socket_pipe` returns `f64`/`NR_F64`, which the scanner does not
classify, so it needs no row.

Constants: EXPECTED_ROWS 371 -> 376, EXPECTED_PROVIDERS 322 -> 326.
These describe `main` as it stands at 023dc0b; in-flight
binding-removal PRs that also move `EXPECTED_ROWS` re-derive their own
number at rebase time.
Removes the native uuid binding so `import { v4, parse, stringify, NIL }
from "uuid"` (no perry.compilePackages entry) resolves to the real npm
package compiled from source, per the owner's decision to stop shipping
hand-written Rust reimplementations of npm packages.

The native binding is missing `parse`/`stringify` entirely (a
`parse`/`stringify` roundtrip throws: `bytes` comes back `undefined`),
and `NIL` reads as `undefined` (js_uuid_nil exists in the deleted source
but was never wired into either NativeModSig dispatch table or the API
manifest, so property access on the uuid module namespace fell through
to undefined). v1/v3/v4/v5/validate/version were correct in both.

Per #10678 (duplicate extern "C" exports across perry-ext-*/perry-stdlib
pairs), this binding existed twice: crates/perry-ext-uuid/ (the
governance-tracked binding crate) and crates/perry-stdlib/src/uuid.rs (a
second, independent implementation behind the now-removed bundled-uuid
feature). Both are deleted, along with the 7-entry NativeModSig dispatch
block in native_table/utils_crypto.rs, the well_known_bindings.toml
entry, the "uuid" NATIVE_MODULES entry and its 7 manifest rows, and the
6 Android stub exports.

crypto/random.rs entanglement: crypto.randomUUID()/randomUUID({v7:true})
and nodemailer's message-id generation both call the `uuid` Cargo crate
(uuid::Uuid::new_v4()/now_v7()) directly and unconditionally — neither
site has a cfg(feature) gate. The `uuid` crate dependency in
perry-stdlib/Cargo.toml was therefore never actually optional in
practice even though it was declared `optional = true` behind the
bundled-uuid npm-binding feature; removing that feature without also
dropping `optional = true` would have broken the build the moment
bundled-uuid stopped being enabled. Made `uuid` a required (non-optional)
dependency and retargeted the `ids` feature umbrella to
`["bundled-nanoid"]`. crypto.randomUUID()/randomUUID({v7:true}) and
node:crypto's randomBytes are unaffected — verified below.

Retargeted the one dts-shape regression test that used uuid.v4() as its
zero-arg-module-function fixture (perry-api-manifest's
dts_uuid_v4_has_no_args) to perry/gc.minor(), which is unrelated to any
binding-removal churn.

Built on perrymaster (--profile perry-dev). A real `npm install uuid`
project (no perry.compilePackages entry) exercising v1/v4/v5/v3,
validate/version, a parse/stringify roundtrip, and NIL, diffed against
`node --experimental-strip-types` (Node 26.5.1): byte-for-byte identical,
including the deterministic v5/v3 (name+namespace) values. Confirmed
against a pristine origin/main (8df83f8) baseline build that the same
program crashes there: `NIL: undefined`, `parse instanceof Uint8Array:
false`, then `TypeError: Cannot read properties of undefined (reading
'length')` on the roundtrip — reproducing the reported bug exactly.
crypto.randomUUID() and node:crypto's randomBytes/randomUUID were
re-checked against the fix and still work (both call the `uuid` crate
directly, unaffected by the binding removal).

- cargo build --profile perry-dev -p perry -p perry-runtime-static -p
  perry-stdlib-static: clean; confirmed .a mtimes moved.
- cargo check --workspace --all-targets (host-compatible exclusion set
  via workspace_architecture.py --print-excluded-scope) under
  -D warnings: clean.
- cargo test -p perry-api-manifest: 39+4 passing (after retargeting the
  uuid-fixture test).
- cargo test -p perry-codegen --test manifest_consistency: 5/5 passing.
- cargo test -p perry --bin perry -- well_known: 27/27 passing.
- cargo test -p perry-hir: full suite passing (test_lower_native_module_
  registration uses "uuid" only as synthetic example data for a generic
  register/lookup mechanism — unaffected by the registry removal).
- python3 scripts/binding_governance.py --check: OK (39 extension
  crates).
- node scripts/binding_pins.mjs --check: OK (37 pinned, lock-step
  holds).
- python3 scripts/workspace_architecture.py --check: OK.
- python3 scripts/native_result_ledger.py: OK, 371 rows/322 providers
  unchanged (none of uuid's dispatch rows used a ledger-tracked NR_*
  kind).
- python3 scripts/string_payload_access_inventory.py --write-baseline:
  perry-stdlib inline-offset 40 -> 38 (uuid.rs's own 2 sites).
- Regenerated docs/api/perry.d.ts + docs/src/api/reference.md
  (perry --print-api-manifest) and docs/src/native-libraries/
  governance.md (binding_governance.py --table) from the fixed manifest.
- cargo fmt --all -- --check: clean.
- scripts/run_lint_gates.sh (SKIP_COMPILE_GATES=1): 76 of 77 passed; the
  one failure (Public benchmark evidence freshness) is the pre-existing,
  known-red-on-every-PR gate per this campaign's contract.

- Compile tier of run_lint_gates.sh (known-red on Linux per this
  campaign's contract).
- Full gap suite (host stalls under auto-optimize per contract).
- test-files/test_parity_uuid.ts is already excluded from the parity
  gate (test-parity/known_failures.json, "ci-env": Node's own oracle run
  fails ERR_MODULE_NOT_FOUND because uuid was never added to the repo's
  root package.json/package-lock.json — the same pre-existing gap
  documented for nanoid, #8271). Its `@covers` comment now points at a
  deleted file (crates/perry-stdlib/src/uuid.rs); leaving it untouched,
  matching how the sibling nanoid PR (#10693) left its own equivalent
  parity fixture alone.
- No version bump / CLAUDE.md edit — per this campaign's convention, the
  maintainer bumps at merge time.
- crates/perry-ui-android/src/stdlib_stubs.rs was edited to remove the
  matching 6 js_uuid_* stub exports (following the established pattern
  from the sibling removals) but not build-verified — this host has no
  Android NDK and the package is excluded from the host-compatible
  check scope.
@proggeramlug
proggeramlug merged commit 053b9cc into main Sep 19, 2026
23 of 25 checks passed
@proggeramlug
proggeramlug deleted the train225r branch September 19, 2026 16:53
@coderabbitai

coderabbitai Bot commented Sep 19, 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: b8329a1c-88fd-41fd-90f0-712ff07d7d0f

📥 Commits

Reviewing files that changed from the base of the PR and between d4ef732 and 1376bbf.

⛔ 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 (24)
  • CLAUDE.md
  • Cargo.toml
  • changelog.d/10701-uuid-native-binding-removal.md
  • changelog.d/10740-native-result-ledger-net-socket-providers.md
  • crates/perry-api-manifest/src/emit.rs
  • crates/perry-api-manifest/src/entries.rs
  • crates/perry-api-manifest/src/entries/part_1.rs
  • crates/perry-codegen/src/lower_call/native_table/utils_crypto.rs
  • crates/perry-ext-uuid/Cargo.toml
  • crates/perry-ext-uuid/src/lib.rs
  • crates/perry-stdlib/Cargo.toml
  • crates/perry-stdlib/src/lib.rs
  • crates/perry-stdlib/src/uuid.rs
  • crates/perry-ui-android/src/stdlib_stubs.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
  • scripts/native_result_ledger.py
  • scripts/string_payload_access_baseline.txt
  • scripts/unrooted_local_shape_baseline.json
  • workspace-architecture.json
 _________________________________________________________________________________________
< The three laws of code review: 1. Find bugs. 2. Find more bugs. 3. Find even more bugs. >
 -----------------------------------------------------------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
✨ 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.

native_result_ledger.py is red on pristine main (expected 371, found 376), and its path filter means it can only fail on an unrelated PR

1 participant