Epic: every registered API is real, or it fails loud
Full-tree stub audit (2026-06-10, runtime + stdlib + api-manifest, verified against current main). A "stub" here means: an API that is registered and callable by name but returns a no-op, a hardcoded/fake value, or silently wrong behavior. For a native compiler, "compiles fine, runs wrong" is the worst failure mode — this epic exists so that by v1.0 no API can lie. (Spun out of the stable-release/versioning discussion; this is a 0.8-line "honest surface" gate.)
Policy (the actual deliverable)
Every API is in exactly one of three states, machine-readable in the manifest and enforced by CI:
- Real — behaves like Node.
- Partial — documented subset; out-of-subset input throws, never silently degrades.
- Stub — flagged
stub: true, emits perry_stub_warn on first call, visible in .d.ts/reference docs, throws under PERRY_STRICT_STUBS=1.
Keystone issue: #4918 (manifest stub flag is never set; two stub registries don't know about each other).
Stub inventory — sub-issues
| Issue |
Cluster |
Severity |
| #4911 |
node:dns + node:dgram loopback-only fakes |
SILENT-LIE |
| #4912 |
child_process.spawn() returns null; exec() secretly synchronous |
LOUD + SILENT-LIE |
| #4913 |
Atomics.wait/notify/waitAsync non-blocking fakes (post-#4794) |
SILENT-LIE |
| #4914 |
node:cluster — no socket/listening-handle distribution |
SILENT-LIE |
| #4915 |
Web Streams BYOB readers + ByteLengthQueuingStrategy throw (post-#1545) |
LOUD |
| #4916 |
v8 heap snapshot = empty-but-valid graph; inspector/repl look real |
SILENT-LIE |
| #4917 |
stdlib adapters: ignored options + success-returning no-ops (zlib/http.Agent/mongodb/mysql2/pg/worker_threads/fastify/backoff) |
mixed |
| #4918 |
Keystone: manifest stub: true population + CI cross-check + strict mode |
infra |
Pre-existing open issues that are stub-class (tracked there, listed for completeness)
Found-but-not-filed (intentional / by-design, no action unless policy changes)
Audit notes (claims checked and dropped)
Done when
All eight sub-issues closed (or individually re-triaged with rationale here), and the #4918 CI gate is the thing preventing recurrence — not this list.
Epic: every registered API is real, or it fails loud
Full-tree stub audit (2026-06-10, runtime + stdlib + api-manifest, verified against current
main). A "stub" here means: an API that is registered and callable by name but returns a no-op, a hardcoded/fake value, or silently wrong behavior. For a native compiler, "compiles fine, runs wrong" is the worst failure mode — this epic exists so that by v1.0 no API can lie. (Spun out of the stable-release/versioning discussion; this is a 0.8-line "honest surface" gate.)Policy (the actual deliverable)
Every API is in exactly one of three states, machine-readable in the manifest and enforced by CI:
stub: true, emitsperry_stub_warnon first call, visible in.d.ts/reference docs, throws underPERRY_STRICT_STUBS=1.Keystone issue: #4918 (manifest
stubflag is never set; two stub registries don't know about each other).Stub inventory — sub-issues
node:dns+node:dgramloopback-only fakeschild_process.spawn()returns null;exec()secretly synchronousAtomics.wait/notify/waitAsyncnon-blocking fakes (post-#4794)node:cluster— no socket/listening-handle distributionByteLengthQueuingStrategythrow (post-#1545)stub: truepopulation + CI cross-check + strict modePre-existing open issues that are stub-class (tracked there, listed for completeness)
WeakRef/FinalizationRegistrynot actually weak ("API exists, semantics lie")@perry_closure_*globals → linked-but-crashing binary (the linker-level analog of a stub: fail loud at link time)Found-but-not-filed (intentional / by-design, no action unless policy changes)
stdlib_stubs.rslink-time fallbacks (WebSocket/fetch/readline when perry-stdlib isn't linked) — legitimate, but should all route throughperry_stub_warn(folded into api-manifest: stub flag exists but is never set — populate it, cross-check with stub_diag, and surface in docs + a strict mode #4918).ui_harmonyos_stubs.rs— platform-gated zero-returning UI symbols (perry/ui FFI symbols undefined on --target harmonyos (perry_ui_embed_nsview, others) — block on .so load #395); exactly what the manifeststubfield was invented for.node:vmSourceTextModule — throwsERR_PERRY_VM_UNIMPLEMENTEDwith issue pointer; this is the model behavior the rest should copy.node:stream_read()throwing "not implemented" — correct Node semantics, not a stub.Audit notes (claims checked and dropped)
AsyncLocalStorage/async_hooks) — real since AsyncLocalStorage: real async-context tracking across await / microtasks / timers #788/async_hooks: real createHook lifecycle + asyncId tracking #789 closed (May 16); CLAUDE.md's "name-only stubs" note is stale and should be updated.node:tty"always reports non-TTY" — not confirmed; tty raw-mode work (TUI gap: readline + tty.setRawMode + raw-mode stdin reader #347/process.stdin: support listener removal and lifecycle detach for TUI teardown #3962) landed for the ink push.node:netloopback-only — not confirmed on current main; dropped from node:dns + node:dgram are loopback-only fakes — implement real network I/O behind a deterministic-mode flag #4911.Done when
All eight sub-issues closed (or individually re-triaged with rationale here), and the #4918 CI gate is the thing preventing recurrence — not this list.