Skip to content

fix(api-manifest): closes #513 — enumerate every native module so R005 covers 100% of supported surface (v0.5.600) - #523

Merged
proggeramlug merged 1 commit into
mainfrom
fix-issue-513
May 6, 2026
Merged

fix(api-manifest): closes #513 — enumerate every native module so R005 covers 100% of supported surface (v0.5.600)#523
proggeramlug merged 1 commit into
mainfrom
fix-issue-513

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Summary

Closes #513 (followup to #463). The unimplemented-API gate was conditioned on module_has_any_entries(M) && module_has_symbol(M, prop).is_none() — modules with zero manifest entries silently fell through to the old permissive behaviour, leaving the same class of bug Justin originally hit on crypto.subtle in #455 alive on un-enumerated modules. ~20 modules in NATIVE_MODULES had zero entries; five well-known aliases weren't even registered as native modules.

This PR ships:

  • Backfill in crates/perry-api-manifest/src/entries.rs — ~250 new entries covering the gap modules (fs, util, stream, child_process, tty, http, https, axios, node-fetch, bignumber.js, node-cron, perry/ui, perry/system, perry/i18n, perry/updater, perry/media, perry/plugin, perry/widget, plus the well-known aliases redis / date-fns / streams / rate-limiter-flexible / fetch). perry/ui + perry/system + perry/i18n + perry/updater + perry/media are auto-derived from PERRY_*_TABLE in crates/perry-dispatch. Coverage went from 397 entries / 45 modules to 638 entries / 64 modules.

  • Reverse-direction drift tests in crates/perry-codegen/tests/manifest_consistency.rs:

    • every_native_module_has_at_least_one_manifest_entry — walks NATIVE_MODULES, fails CI if any entry has zero manifest rows (allow-list: dotenv/config, side-effect-only sub-path).
    • every_well_known_binding_has_manifest_entry — parses crates/perry/well_known_bindings.toml, fails CI if any routed module name lacks manifest coverage.
  • R005 parity sweep in crates/perry-hir/tests/unimplemented_api_check.rs::every_supported_module_rejects_bogus_member — compiles import * as m from "<module>"; const x = m.__perry_known_bogus_member_513__; for every NATIVE_MODULES entry and asserts the R005 / Compile-time error for unimplemented Node / Web APIs #463 error fires.

The previously-permissive module_with_no_manifest_entries_is_permissive test that documented the pre-#513 fall-through is replaced with supported_module_with_unknown_member_is_rejected, asserting the new strict behaviour.

docs/src/api/reference.md and docs/api/perry.d.ts regenerated through scripts/regen_api_docs.sh — the api-docs-drift CI gate from v0.5.560 keeps these in sync going forward.

Test plan

  • cargo test --release -p perry-codegen --test manifest_consistency — 4 / 4 pass (2 new reverse-direction tests).
  • cargo test --release -p perry-hir --test unimplemented_api_check — 8 / 8 pass (1 replaced + 1 new parity sweep test).
  • cargo test --release -p perry-api-manifest — 7 / 7 pass.
  • End-to-end smoke: fs.writeFileSync(p, "ok") + path.join("/tmp", "x") continue to compile + run; fs.bogusMethod errors with the R005-style message; perry/ui.bogusWidget errors identically.
  • ./scripts/regen_api_docs.sh — produces no further diff after running with the manifest changes (drift gate happy).
  • Parity sweep (98.5%, no regressions vs main): 206 pass / 3 known fails (test_edge_destructuring, test_edge_objects_records, test_gap_object_methods) / 1 known compile fail (test_issue_446_import_type_method_typeof) / 13 skipped. The 3 jsruntime-related compile fails surfaced in the worktree because libperry_jsruntime.a wasn't pre-built — environmental, not a regression.
  • CI lint / fmt / test gates pass on this PR.

Refs #455, #463, #466 (Phase 2 — adding new modules now auto-enrolls them via the reverse drift gate).

…5 covers 100% of supported surface (v0.5.600)

The unimplemented-API gate from #463 is `module_has_any_entries(M) && module_has_symbol(M, prop).is_none()` —
modules with zero manifest entries silently fell through to the old permissive behaviour, leaving the same class
of bug Justin hit in #455 alive on un-enumerated modules. ~20 modules in NATIVE_MODULES had zero entries
(`fs`, `util`, `stream`, `child_process`, `tty`, `http`, `https`, `axios`, `node-fetch`, `bignumber.js`,
`node-cron`, `perry/ui`, `perry/system`, `perry/i18n`, `perry/updater`, `perry/media`, `perry/plugin`,
`perry/widget`); five well-known aliases (`redis` / `date-fns` / `streams` / `rate-limiter-flexible` / `fetch`)
weren't even registered as native modules.

Three coordinated changes:

1. `crates/perry-api-manifest/src/entries.rs` — backfill ~250 entries covering the gap modules. perry/ui +
   perry/system + perry/i18n + perry/updater + perry/media are auto-derivable from PERRY_*_TABLE in
   crates/perry-dispatch; perry/plugin from PERRY_PLUGIN_TABLE in crates/perry-codegen/src/lower_call.rs.
   fs / util / stream / child_process / tty / buffer / url get method+class entries reflecting what
   perry-runtime + perry-stdlib actually implement. The HTTP-client trio (axios / node-fetch / http / https)
   covers the standard verb methods plus class constructors. The well-known aliases (redis / date-fns /
   bignumber.js / node-cron / streams / rate-limiter-flexible / fetch) get entries mirroring their canonical
   module so `import { Redis } from 'redis'` works the same way as `import { Redis } from 'ioredis'`.
   Coverage went from 397 entries / 45 modules to 638 entries / 64 modules.

2. `crates/perry-codegen/tests/manifest_consistency.rs` — two new reverse-direction drift tests.
   `every_native_module_has_at_least_one_manifest_entry` walks NATIVE_MODULES and asserts each one has at
   least one manifest entry (allow-list: `dotenv/config`, side-effect-only sub-path with no value binding).
   `every_well_known_binding_has_manifest_entry` parses well_known_bindings.toml and asserts each routed
   module name has manifest coverage. Both fail loudly with the missing module names + the fix recipe, so
   adding a future native module without manifest entries breaks CI before the PR ships.

3. `crates/perry-hir/tests/unimplemented_api_check.rs` — new `every_supported_module_rejects_bogus_member`
   parity sweep that compiles `import * as m from "<module>"; const x = m.__perry_known_bogus_member_513__;`
   for every entry in NATIVE_MODULES and asserts the R005 / #463 error fires (skip list: `dotenv/config` +
   the external `tursodb` / `iroh` bindings whose value-binding shape doesn't trigger the gate in the
   isolated HIR test). The previously-permissive `module_with_no_manifest_entries_is_permissive` test that
   documented the pre-#513 fall-through is replaced with `supported_module_with_unknown_member_is_rejected`.

End-to-end smoke verified: `import * as fs from "fs"; const x = fs.bogusMethod;` errors with the R005-style
message naming the offending property; `import * as ui from "perry/ui"; ui.bogusWidget;` errors identically;
legitimate `fs.writeFileSync(p, "ok")` + `path.join("/tmp", "x")` continue to compile + run unchanged.
docs/src/api/reference.md (now 638 entries / 64 modules) and docs/api/perry.d.ts regenerated through
scripts/regen_api_docs.sh — the api-docs-drift CI gate from v0.5.560 keeps these in sync going forward.

Closes the credibility gap from #513's "v0.5.585 release implies completeness it doesn't have yet" framing —
`perry --print-api-manifest` now genuinely reflects the supported surface, and a user on `async_hooks` /
`dgram` / etc. gets the same #463 compile-time error every other module produces.
@proggeramlug
proggeramlug merged commit 74802c7 into main May 6, 2026
6 of 10 checks passed
@proggeramlug
proggeramlug deleted the fix-issue-513 branch May 6, 2026 12:51
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.

API manifest: enumerate remaining stdlib modules so unimplemented-API check (#463) covers 100% of supported surface

1 participant