chore: merge train 225 (v0.5.1604) - #10748
Merged
Merged
Conversation
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.
|
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 (24)
✨ 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 was referenced Sep 19, 2026
Closed
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 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
tooling: classify the four unclassifiednet.Socketproviders in the native result ledgerrefactor(stdlib): remove the uuid native binding, compile the real package from source#10740 fixes a gate that was red on
mainfor four releases — and was hiding a real defectscripts/native_result_ledger.pyfailed on pristinemainwithexpected 371 classified rows, found 376. Attributed by counting rows per file at4715bc2fa1(green) against91c6a05012(first red): onlynative_table/net_events.rsmoved, 53 → 58, from #10658'snet.Socketsurface 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 unclassifiedresult_kindmisrepresents 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: i64argument unchanged — a key intostatics::sockets(), not a heap address — soNR_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_PROVIDERSreaches the coverage check and names the symbol; misclassifying one asNR_GCPTRis 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.lockregenerated from the resolved manifest: noperry-ext-uuidentries, no stale versions,cargo metadataaccepting the tree.scripts/unrooted_local_shape_baseline.jsonre-derived with the detector now onmain: 580 → 578, because removing the uuid binding drops two findings.--checkagrees 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-targetsunder-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.lintcompleted its full 6-of-6 compile tier with nothing outside the known-red public-baseline step.Issues resolved
Closes #10738