From 207bb816dc9834323b512e1f8218887370c26cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Sat, 19 Sep 2026 17:21:19 +0200 Subject: [PATCH 1/2] fix(tooling): classify four net.Socket providers and unmask the ledger 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 023dc0b653; in-flight binding-removal PRs that also move `EXPECTED_ROWS` re-derive their own number at rebase time. --- scripts/native_result_ledger.py | 13 +++++++++++-- scripts/native_result_ledger.tsv | 4 ++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/scripts/native_result_ledger.py b/scripts/native_result_ledger.py index 5b3e166c1a..7ca06de8c5 100644 --- a/scripts/native_result_ledger.py +++ b/scripts/native_result_ledger.py @@ -23,8 +23,17 @@ # prose comments in fastify.rs, while one real row uses the positional `cr(...)` # helper, leaving 371 executable declarations. The scanner parses declarations, # not comments, and includes that helper row. -EXPECTED_ROWS = 371 -EXPECTED_PROVIDERS = 322 +# +# +5 rows / +4 providers since then (#10738): #10658's `net.Socket` surface +# cluster landed in merge train 221 and grew `native_table/net_events.rs` from +# 53 to 58 typed rows, carrying four new runtime symbols — +# `js_ext_net_socket_on` (two rows: `on` and `addListener` share the symbol), +# `js_net_socket_prepend_listener`, `js_net_socket_prepend_once_listener` and +# `js_net_socket_unpipe`. Each returns its `handle: i64` argument unchanged, a +# `next_id_or_throw()` registry id rather than a heap address, so all four are +# NR_HANDLE_ID. +EXPECTED_ROWS = 376 +EXPECTED_PROVIDERS = 326 KINDS = { "NR_GCPTR", "NR_NULLABLE_GCPTR", diff --git a/scripts/native_result_ledger.tsv b/scripts/native_result_ledger.tsv index 45bcc5c586..170454102d 100644 --- a/scripts/native_result_ledger.tsv +++ b/scripts/native_result_ledger.tsv @@ -74,6 +74,7 @@ js_events_on NR_GCPTR crates/perry-ext-events/src/module_on.rs *mut ArrayHeader js_events_once NR_GCPTR crates/perry-ext-events/src/lib.rs *mut Promise js_ext_net_create_server NR_HANDLE_ID crates/perry-ext-net/src/lib.rs i64 js_ext_net_socket_connect NR_HANDLE_ID crates/perry-ext-net/src/lib.rs i64 +js_ext_net_socket_on NR_HANDLE_ID crates/perry-ext-net/src/handle_exports.rs i64 js_ext_net_socket_once NR_HANDLE_ID crates/perry-ext-net/src/handle_exports.rs i64 js_ext_tls_connect NR_HANDLE_ID crates/perry-ext-net/src/tls.rs i64 js_fastify_app_server NR_HANDLE_ID crates/perry-ext-fastify/src/app.rs Handle @@ -161,6 +162,8 @@ js_net_socket_address_new NR_HANDLE_ID crates/perry-ext-net/src/classes.rs i64 js_net_socket_alloc NR_HANDLE_ID crates/perry-ext-net/src/lib.rs i64 js_net_socket_listeners NR_GCPTR crates/perry-ext-net/src/lifecycle.rs i64 js_net_socket_noop_self NR_HANDLE_ID crates/perry-ext-net/src/option_setters.rs i64 +js_net_socket_prepend_listener NR_HANDLE_ID crates/perry-ext-net/src/lifecycle.rs i64 +js_net_socket_prepend_once_listener NR_HANDLE_ID crates/perry-ext-net/src/lifecycle.rs i64 js_net_socket_raw_listeners NR_GCPTR crates/perry-ext-net/src/lifecycle.rs i64 js_net_socket_ref NR_HANDLE_ID crates/perry-ext-net/src/option_setters.rs i64 js_net_socket_remove_all_listeners NR_HANDLE_ID crates/perry-ext-net/src/lifecycle.rs i64 @@ -169,6 +172,7 @@ js_net_socket_reset_and_destroy NR_HANDLE_ID crates/perry-ext-net/src/lifecycle. js_net_socket_set_encoding NR_HANDLE_ID crates/perry-ext-net/src/option_setters.rs i64 js_net_socket_set_timeout NR_HANDLE_ID crates/perry-ext-net/src/option_setters.rs i64 js_net_socket_set_type_of_service NR_HANDLE_ID crates/perry-ext-net/src/option_setters.rs i64 +js_net_socket_unpipe NR_HANDLE_ID crates/perry-ext-net/src/pipe.rs i64 js_net_socket_unref NR_HANDLE_ID crates/perry-ext-net/src/option_setters.rs i64 js_node_forge_certificate_from_pem NR_JS_VALUE crates/perry-ext-node-forge/src/lib.rs JsValue js_node_forge_create_certificate NR_JS_VALUE crates/perry-ext-node-forge/src/lib.rs JsValue From c15045cfea485a9233aae54bb448282abbbadea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Sat, 19 Sep 2026 17:22:23 +0200 Subject: [PATCH 2/2] docs: changelog fragment for #10740 --- ...tive-result-ledger-net-socket-providers.md | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 changelog.d/10740-native-result-ledger-net-socket-providers.md diff --git a/changelog.d/10740-native-result-ledger-net-socket-providers.md b/changelog.d/10740-native-result-ledger-net-socket-providers.md new file mode 100644 index 0000000000..e37592c059 --- /dev/null +++ b/changelog.d/10740-native-result-ledger-net-socket-providers.md @@ -0,0 +1,36 @@ +Fix `scripts/native_result_ledger.py`, which was red on `main` and blocking +the path-filtered `Native Result Ledger` workflow on every PR touching +`crates/perry-codegen/src/lower_call/native_table/**` or the ledger files. + +Two defects, one masking the other. `EXPECTED_ROWS` was stale at 371 while +#10658's `net.Socket` surface cluster (merge train 221) grew +`native_table/net_events.rs` from 53 to 58 typed rows. Behind that stale +count sat the real problem: those five rows carry four runtime symbols that +had no entry in `scripts/native_result_ledger.tsv`, so the codegen table +declared a result class the provider inventory had no opinion about — and an +unclassified `result_kind` misrepresents to the GC what a native call +returns. Because `check()` raises on its first failure, the row-count check +never let the classification-coverage check run, so bumping the constant +alone would have turned the gate green and shipped the real defect. + +Each provider was read rather than 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 — so all four are +`NR_HANDLE_ID` (`NativeRetKind::HandleId`, "an integer registry id or +provider sentinel"): + +- `js_ext_net_socket_on` — `crates/perry-ext-net/src/handle_exports.rs` +- `js_net_socket_prepend_listener` — `crates/perry-ext-net/src/lifecycle.rs` +- `js_net_socket_prepend_once_listener` — `crates/perry-ext-net/src/lifecycle.rs` +- `js_net_socket_unpipe` — `crates/perry-ext-net/src/pipe.rs` + +Four symbols across five rows: `js_ext_net_socket_on` backs both the `on` and +the `addListener` rows. The sibling `js_net_socket_pipe` returns `f64` under +`ret: NR_F64`, which the scanner does not classify, so it needs no row. + +`EXPECTED_ROWS` 371 → 376 and `EXPECTED_PROVIDERS` 322 → 326, with the +existing explanatory comment extended to attribute the delta to #10658 and +train 221. The gate was re-proved to bite: deleting a new row reddens it on +the provider count, deleting it with the count adjusted reddens it naming the +symbol, and misclassifying `js_net_socket_unpipe` as `NR_GCPTR` reddens it on +the table/provider disagreement.