refactor(stdlib): remove nanoid native binding - #10693
proggeramlug wants to merge 2 commits into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (13)
💤 Files with no reviewable changes (8)
🚧 Files skipped from review as they are similar to previous changes (1)
Included review availability: Your plan provides up to 8 included reviews per hour; 5 remain after this review. 📝 WalkthroughWalkthroughThe native NanoID binding and duplicate runtime implementations were removed. Manifest, code-generation, feature, registry, workspace, Android stub, and documentation references were updated. NanoID imports now compile from npm package source. ChangesNanoID binding removal
Priority: ➖ Normal Estimated code review effort: 2 (Simple) | ~10 minutes Change: Bug fix · Severity of issue fixed: Medium 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ 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 |
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.
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.
|
Heads-up before this is queued: this PR's recorded workspace baseline is stale and will fail It records Full table and reasoning in #10739. The short version, for whoever rebases this:
Also relevant to the acceptance run whenever it happens: #10735 is live on main — |
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.
7adf46f to
8cf9cb1
Compare
customAlphabet(alphabet, size) is documented to return a generator function; native customAlphabet instead returns the generated id string directly (js_nanoid_custom's own doc comment: "For simplicity, we combine this into one call"), so the only documented usage -- const gen = customAlphabet(...); gen(); -- crashes with TypeError: value is not a function. Per #10678 (duplicate extern "C" exports across perry-ext-*/perry-stdlib pairs), this binding existed twice: crates/perry-ext-nanoid/ (governance- tracked) and crates/perry-stdlib/src/nanoid.rs (a second, independent implementation behind the default-on bundled-nanoid feature, exporting the same js_nanoid/js_nanoid_sized/js_nanoid_custom symbols). customAlphabet is declared to codegen (data_stores.rs's js_nanoid_custom) but has no call-site wiring anywhere in perry-codegen -- no NativeModSig row, no lower_call special case. Only plain nanoid(size) had a dispatch row (native_table/utils_crypto.rs, routing to js_nanoid_sized), consistent with customAlphabet not being a first-class compiled call at all. Removed both crates, the 1-entry NativeModSig dispatch row, the 2 js_nanoid* FFI declarations, the well_known_bindings.toml entry, the "nanoid" NATIVE_MODULES entry + manifest row, the bundled-nanoid stdlib feature, and 2 Android stub exports. DELETED the shipped_unproven_bindings_are_partial test rather than emptying it. Its subject population was exactly the hand-written wrappers shipped without proven upstream parity: uuid (#10701), dotenv (#10691, landed in train 227) and nanoid (here). With the last one gone the array would read `for name in []` -- a test that compiles, runs, asserts nothing and reports green forever, which is failure mode #4 in CLAUDE.md's "four ways a gate can be unable to fail". Coverage is not lost: shipped_subset_bindings_are_partial is a separate test and still asserts the same property for undici, node-forge, lru-cache and qs. Verified the deletion orphans nothing -- the test module is `use super::*`, lookup_well_known has 9 other callers, BindingCompat::Partial has 5 other uses, and nothing in the tree keys on the test's name. The "ids" umbrella is now EMPTY. It was retargeted to ["bundled-nanoid"] when #10701 removed uuid (train 225); removing bundled-nanoid leaves it with no members, so it is kept as `ids = []` -- an intentionally harmless no-op that preserves `--features ids` for existing callers rather than breaking them. The stale comments that described the two-member split (perry-stdlib/Cargo.toml, perry-stdlib/src/lib.rs, stdlib_features.rs) are rewritten to say so. perry-stdlib's `uuid` crate dependency is untouched: #10701 already made it non-optional because crypto/random.rs calls it unconditionally. test-files/test_parity_nanoid.ts (the exact customAlphabet(...)(); reproduction) is already excluded from the parity gate -- known_failures.json classifies it "ci-env": Node's own oracle fails with ERR_MODULE_NOT_FOUND in CI because nanoid was never added to the repo's root package.json, so npm ci never installs it. Not touched -- provisioning a real npm dependency in the root package.json is out of scope for a binding-removal PR, and the test remains excluded before and after this change for the same underlying reason. Every absolute count re-derived from its own script against the resolved tree, never carried across the rebase and never hand-merged: workspace-architecture.json 77 -> 76 members, externalize 28 -> 27, keep 44 (scripts/workspace_architecture.py; git auto-merged this file with NO conflict and left the stale 77/28, which the script caught); docs/api/perry.d.ts 2065 entries/131 modules -> 2064/130 and docs/src/api/reference.md 3007/133 -> 3006/132, both regenerated by running the built binary's --print-api-manifest rather than editing the headers; Cargo.lock regenerated with `cargo metadata`. native_result_ledger (376 rows/326 providers), unrooted_local_shape (578) and string_payload_access (perry-stdlib inline-offset 37) confirmed unchanged by running them, not by assuming. Rebased onto v0.5.1606 (train 227). Conflicts were all of the form "main deleted dotenv, this branch deleted nanoid, in one hunk"; every one was resolved to main's current content minus nanoid's own entries, which is neither side.
8cf9cb1 to
9a400cc
Compare
|
Landed in merge train 228 (#10764), released as v0.5.1607 — main is now Closing rather than merging is how trains work here: both PRs were cherry-picked onto one tree, validated together, and landed under the train's own commit, so GitHub cannot mark this one merged even though your change is on main. Counts re-derived on the assembled tree, not carried: workspace 76/27/44, ledger 376/326, unrooted 578. Worth recording that Validation: all nine cheap gates, |
Summary
Removes the native
nanoidbinding soimport { nanoid, customAlphabet } from "nanoid"(noperry.compilePackagesentry) resolves to the real npmpackage, compiled from source, per the owner's decision to stop shipping
hand-written Rust reimplementations of npm packages.
The bug
customAlphabet(alphabet, size)is documented to return a generatorfunction — call it repeatedly to mint ids. Native
customAlphabetinsteadreturns the generated id string directly (the FFI function
js_nanoid_custom's own doc comment admits it: "For simplicity, we combinethis into one call: nanoid.custom(alphabet, size)"), so the only documented
usage —
const gen = customAlphabet(...); gen();— crashes withTypeError: value is not a function.What was found and removed
Per #10678 (duplicate
extern "C"exports acrossperry-ext-*/perry-stdlibpairs), this binding existed twice:
crates/perry-ext-nanoid/— the governance-tracked binding crate, wiredinto
well_known_bindings.toml's[bindings.nanoid].crates/perry-stdlib/src/nanoid.rs(62 lines) — a second, independentimplementation behind the
bundled-nanoidfeature (default-on via theidsumbrella), exporting the samejs_nanoid/js_nanoid_sized/js_nanoid_customsymbols.One subtlety:
customAlphabetis declared to codegen(
runtime_decls/stdlib_ffi/data_stores.rs'sjs_nanoid_custom) but hasno call-site wiring anywhere in perry-codegen — no
NativeModSigrow,no
lower_callspecial case. Only plainnanoid(size)had a dispatch row(
native_table/utils_crypto.rs, routing tojs_nanoid_sized). This isconsistent with the bug report:
customAlphabetisn't a first-classcompiled call at all.
Removed both crates, the 1-entry
NativeModSigdispatch row(
nanoid.nanoid→js_nanoid_sized), the 2js_nanoid*FFI declarations inruntime_decls/stdlib_ffi/data_stores.rs, thewell_known_bindings.tomlentry, the
"nanoid"NATIVE_MODULESentry and its manifest row, thebundled-nanoidstdlib feature, and the 2 Android stub exports.The
idsumbrella is now empty. It was retargeted to["bundled-nanoid"]when #10701 removed uuid (train 225); removingbundled-nanoidleaves it with no members, so it is kept asids = []—an intentionally harmless no-op that preserves
--features idsforexisting callers rather than breaking them. The three comments that still
described the two-member split (
perry-stdlib/Cargo.toml,perry-stdlib/src/lib.rs,stdlib_features.rs) are rewritten to say so.perry-stdlib'suuidcrate dependency is untouched: #10701 alreadymade it non-optional because
crypto/random.rscalls it unconditionally.Why
shipped_unproven_bindings_are_partialis deleted, not emptiedThis test asserted that the hand-written wrapper bindings we shipped without
proving upstream parity stay marked
compat = "partial". Its subjectpopulation was exactly those wrappers:
uuid(removed in #10701),dotenv(#10691) and
nanoid(this PR). With the last one gone the loop has nonames left to iterate.
Leaving it as
for name in [] { ... }would be worse than removing it. Itwould compile, run, assert nothing and report green forever — a test whose
subject never executes, which is failure mode #4 in CLAUDE.md's "four ways a
gate can be unable to fail". A future reader would reasonably believe the
posture was still covered.
Coverage is not lost.
shipped_subset_bindings_are_partialis a separatetest and still asserts the same property for the four documented-subset
bindings that remain:
undici,node-forge,lru-cacheandqs. If a newunproven wrapper is ever shipped, the right move is a new test with a real
subject, not the resurrection of an empty loop.
Already-known, not touched
test-files/test_parity_nanoid.ts(the exactcustomAlphabet(...)();reproduction) is already excluded from the parity gate —
test-parity/known_failures.jsonclassifies itci-env: Node's own oraclerun fails with
ERR_MODULE_NOT_FOUNDin CI becausenanoidwas never addedto the repo's root
package.json/package-lock.json, sonpm cineverinstalls it (confirmed: no
nanoidentry in the rootpackage.json).Before this PR, Perry's side of this fixture worked anyway because the
bare-specifier import bypassed
node_modulesentirely viaNATIVE_MODULES.After this PR, the fixture needs a real installed
nanoidon bothsides, which the repo doesn't provision — provisioning it (adding a real npm
dependency to the root
package.json) is out of scope for a binding-removalPR. Not a regression: the test was already excluded before this PR for an
unrelated, already-tracked reason (#8271), and remains excluded after it.
Acceptance test:
customAlphabetused as a generator, nocompilePackagesentry{ "dependencies": { "nanoid": "^5.0.7" } }Installed nanoid 5.1.16 — the version this
^5.0.7range resolves to. Note the registry entry this PR deletes pinnedupstream version = "6.0.0", a different major; checking against that one would have proved nothing about the package users actually get.Built on perrymaster (
--profile perry-dev). Ran the binary and diffedagainst
node --experimental-strip-types(Node 26.5.1): byte-for-byteidentical —
customAlphabet(...)now returns an actual function, andcalling it repeatedly succeeds, matching Node exactly.
Verification
Re-measured on the rebase onto v0.5.1606 (train 227), macOS arm64,
--release. Every absolute count below was re-derived from its ownscript against the resolved tree, never carried across the rebase:
cargo build --release -p perry -p perry-runtime-static -p perry-stdlib-staticin one invocation: clean..amtimes moved(
libperry_runtime.a00:08:49,libperry_stdlib.a00:10:59, both afterthe last source edit at 00:06:32), and
nmshows zerojs_nanoid*symbols in either archive or in the acceptance binary.
cargo test --release -p perry --bin perry -- well_known: 25/25passing (was 27 before train 227; 227's dotenv removal deleted
dotenv_is_registered, and this PR deletesshipped_unproven_bindings_are_partial).python3 scripts/workspace_architecture.py --check: OK —77 → 76 members, externalize 28 → 27, keep 44. Worth flagging: git
auto-merged
workspace-architecture.jsonwith no conflict and leftthe stale
77/28, because the counts live on different JSON lines fromthe crate entry the removal deletes. The script is what caught it.
python3 scripts/native_result_ledger.py: OK, 376 rows / 326providers unchanged — confirmed by running it, not assumed (nanoid's
one dispatch row was
NR_STR, not a ledger-tracked kind).python3 scripts/unrooted_local_shape.py --check: OK, baseline 578unchanged (nanoid never had an entry).
python3 scripts/string_payload_access_inventory.py: OK,perry-stdlibinline-offset 37 unchanged (nanoid.rshad no sites).python3 scripts/binding_governance.py --check: OK (34 extensioncrates).
node scripts/binding_pins.mjs --check: OK (32 pinned).--print-api-manifest, not by editing the headers:perry.d.ts2065 entries/131 modules → 2064/130,reference.md3007/133 → 3006/132. Both header lines conflictedwith a value that was wrong on both sides.
Cargo.lockregenerated withcargo metadata, never hand-merged;the diff is exactly the three nanoid stanzas.
cargo fmt --all -- --check: clean. This is the gate that matters here —two conflict sites (
entries/part_1.rs,native_table/utils_crypto.rs)have adjacent blocks ending in an identical
),/},, which git foldsinto the common region; an earlier resolution of this branch left a
dangling
method_sig(with no conflict markers and onlycargo fmtrejected it.
scripts/run_lint_gates.sh(SKIP_COMPILE_GATES=1): 78 of 79 ok.The single failure is
benchmarks/ci_public_baseline_check.py, which isknown-red on
main; this PR touches neither file in itsHARNESS_PATHS(
public-baseline-config.json,honest_bench/results/expected.json),so it is pre-existing.
Not run / out of scope
run_lint_gates.sh(known-red on Linux per thiscampaign's contract).
targeted registry/consistency tests plus the direct acceptance test
instead.
CLAUDE.mdedit — per this campaign's convention, themaintainer bumps at merge time.
Summary by CodeRabbit
Bug Fixes
nanoidnow compiles from the upstream npm package, matching Node.js behavior.customAlphabetnow works as a callable generator function.Documentation
nanoidintegration.Removals
nanoidimplementation and runtime integration.nanoidfrom native binding and workspace inventories.