Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
216 commits
Select commit Hold shift + click to select a range
91d1acb
docs: add design for multiple isolated DataWeave engines per process
mlischetti Aug 7, 2026
9e31543
W-23692110: handle-keyed ScriptRuntime registry with per-engine resol…
mlischetti Aug 10, 2026
ba50829
W-23692110: per-engine resolver bridge and handle-based N-API methods
mlischetti Aug 10, 2026
1015beb
W-23692110: per-instance engine handles in Node binding + isolation r…
mlischetti Aug 10, 2026
d776502
W-23692110: fix native library ref-count leak on partial DataWeave.in…
mlischetti Aug 10, 2026
4789129
W-23692110: document independent per-instance engines
mlischetti Aug 10, 2026
27ec812
W-23692110: Make Node engine bridge teardown safe against in-flight o…
mlischetti Aug 10, 2026
5f070dd
W-23692110: Reject invalid engine handles and fix resolver-buffer lea…
mlischetti Aug 10, 2026
5475cbd
W-23692110: Use bridge_finalize in create_engine_with_resolver reject…
mlischetti Aug 10, 2026
2d977d7
Require per-engine ABI symbols at load and align resolver log policy
mlischetti Aug 10, 2026
c71ac9f
Make default resolver-error log fully content-free, not just message-…
mlischetti Aug 10, 2026
2acaf2a
test(node): add lifecycle/error coverage for F1/F4/F6 remediation
mlischetti Aug 10, 2026
285d198
W-23692110: Add native-level test for unknown engine handle contract
mlischetti Aug 10, 2026
596eb8b
chore: remove PR-157 code review process notes from repo
mlischetti Aug 10, 2026
8ace020
docs: add design for cleanup()-during-active-stream deadlock fix
mlischetti Aug 11, 2026
ce6c5de
Add process-global active-op accounting for streaming/transform
mlischetti Aug 11, 2026
32929fa
Make napi_cleanup async: defer isolate teardown until active ops drain
mlischetti Aug 11, 2026
58a0bcf
Block initialize() while an isolate teardown is pending
mlischetti Aug 11, 2026
df2f84a
Fix signal-stealing deadlock: use broadcast instead of signal for op-…
mlischetti Aug 11, 2026
2fb7af7
Change DataWeave.cleanup() to return Promise<void>
mlischetti Aug 11, 2026
b076526
Await the now-async DataWeave.cleanup() in existing tests
mlischetti Aug 11, 2026
5e79ab8
Add cleanup()-during-active-stream/transform deadlock regression tests
mlischetti Aug 11, 2026
9a1843c
Fix napi_initialize deadlock: decrement g_active_ops from the worker …
mlischetti Aug 11, 2026
4d134d0
Document DataWeave.cleanup()'s Promise<void> signature
mlischetti Aug 11, 2026
b8dd857
W-23692110: Unwind pre-spawn state on streaming/transform worker spaw…
mlischetti Aug 11, 2026
fa4d48d
W-23692110: Roll back pending-teardown state on waiter spawn failure
mlischetti Aug 11, 2026
33d1418
fix(native-lib/node): signal read waiter on env==NULL teardown (F3)
mlischetti Aug 11, 2026
c2175ee
W-23692110: Drain in-flight ops via beforeExit before exit fallback
mlischetti Aug 11, 2026
5a172ea
fix: reset cleanupStarted guard after singleton teardown completes
mlischetti Aug 11, 2026
e228223
fix(node): guard uv_thread_join on spawn-failure in three sync paths …
mlischetti Aug 11, 2026
cc46a20
Fix resource leak in write-completion callbacks when env == NULL
mlischetti Aug 11, 2026
24fca45
Only clear global isolate state in teardown_waiter_thread_fn on success
mlischetti Aug 11, 2026
a44707f
W-23692110: Clear initialized in finally so a failed cleanup() doesn'…
mlischetti Aug 12, 2026
e445038
Fix dead-env napi_ref deletion and orphaned-isolate cleanup race
mlischetti Aug 12, 2026
3a1d38d
fix(node): finalize worker-side state when the completion sentinel en…
mlischetti Aug 13, 2026
78e4a79
fix(node): drop tsfn releases already discharged by napi_closing (F1 …
mlischetti Aug 13, 2026
b5c779f
Fix(node): guard cross-thread destroyEngine for resolver-backed engin…
mlischetti Aug 13, 2026
47ee6a5
fix(node): check N-API allocation results in teardown_waiter_create (F3)
mlischetti Aug 13, 2026
ab2e47c
fix(node): coalesce concurrent DataWeave.cleanup() calls (F1)
mlischetti Aug 13, 2026
8799f76
Fix F2: Free the teardown waiter when its completion enqueue fails
mlischetti Aug 13, 2026
e5e693e
Fix napi_initialize deadlock: adopt live isolate during pending teardown
mlischetti Aug 14, 2026
d9146b6
Add deterministic regression test for napi_initialize teardown deadlock
mlischetti Aug 14, 2026
3a0526e
docs: design spec for round-6 instance-lifecycle-state fix (W-23692110)
mlischetti Aug 14, 2026
2e3e340
fix(node): model DataWeave instance lifecycle explicitly (round-6 #1/#3)
mlischetti Aug 14, 2026
01b1136
fix(node): coalesce cleanup() before the not-ready guard (task-1 revi…
mlischetti Aug 14, 2026
dfa7563
fix(node): make stream/transform admission atomic under g_mutex (roun…
mlischetti Aug 14, 2026
5b33e03
fix(node): validate napi_get_value_int64 at handle-read sites (round-…
mlischetti Aug 14, 2026
f5dcde7
fix(node): balance ffi.initialize()/cleanup() in handle-validation test
mlischetti Aug 14, 2026
792c582
docs: design spec for round-7 FFI admission & conversion sweep (W-236…
mlischetti Aug 18, 2026
29552e8
fix(node): reserve g_active_ops across run() isolate window (round-7 #1)
mlischetti Aug 18, 2026
a24af59
fix(node): admit adopted-but-cancelled isolates at all 3 FFI admissio…
mlischetti Aug 18, 2026
9de97a7
fix(node): check every napi_get_value_* status in FFI entrypoints (ro…
mlischetti Aug 18, 2026
49c8014
docs(node): await async cleanup() in external-modules examples (round…
mlischetti Aug 18, 2026
8077355
docs: design spec for round-8 OOM-safe streaming/transform setup (W-2…
mlischetti Aug 18, 2026
1d520ee
fix(node): NULL-check allocations in streaming/transform setup (round…
mlischetti Aug 18, 2026
b4ccb52
docs: mark ga-cleanup backlog item 6 resolved by round-8 OOM fix (W-2…
mlischetti Aug 18, 2026
ff78150
docs: round-9 design spec — engine lifecycle & worker-OOM hardening
mlischetti Aug 18, 2026
f34dd47
docs: correct round-9 spec — #1 is not deterministically testable
mlischetti Aug 18, 2026
2d4ced4
fix(node): OOM-safe worker/callback allocations (round-9 P2)
mlischetti Aug 18, 2026
7030569
fix(node): check N-API resource creation after reservation (round-9 P3)
mlischetti Aug 18, 2026
0e45c2a
fix(node): defer engine registry removal until admitted ops drain (ro…
mlischetti Aug 18, 2026
fd49179
docs(node): fix stale bridge comments after round-9 all-engines recor…
mlischetti Aug 18, 2026
d9bde0e
W-23692110: Remove Java registry entry during Worker/env teardown (ro…
mlischetti Aug 19, 2026
c9989b8
docs: round-10 design spec (worker-teardown dangling resolver ctx + s…
mlischetti Aug 19, 2026
66f7a92
docs: round-11 design spec (engine-pin at admission + all-engines cle…
mlischetti Aug 19, 2026
08078ce
W-23692110: Extract bridge_begin_op_locked for atomic admission-time …
mlischetti Aug 19, 2026
811e8a1
W-23692110: Pin engine in the admission transaction for streaming/tra…
mlischetti Aug 19, 2026
166430e
W-23692110: Pin the engine for synchronous runScriptEngine (round 11 #3)
mlischetti Aug 19, 2026
cb6a061
W-23692110: Register env cleanup hook for every engine + extend owner…
mlischetti Aug 19, 2026
8cc056d
W-23692110: Register process exit hooks once, not per singleton (roun…
mlischetti Aug 19, 2026
5002795
W-23692110: Node integration tests for *_engine unknown/destroyed-han…
mlischetti Aug 19, 2026
bdf103a
W-23692110: Fix initialize/cleanup ref-count imbalance in engine-hand…
mlischetti Aug 19, 2026
9715e91
W-23692110: Fix two cleanup() doc bugs in Node README (round 12 #7)
mlischetti Aug 19, 2026
a6f335b
W-23692110: Add round-12 design spec (worker ref-leak & teardown-race…
mlischetti Aug 19, 2026
78d78b1
W-23692110: Amend round-12 spec #3 to transient-reservation mechanism
mlischetti Aug 19, 2026
e04570f
W-23692110: Extract release_isolate_ref_locked from napi_cleanup (rou…
mlischetti Aug 19, 2026
8756d15
W-23692110: Split bridge_finalize; guard registry attach with transie…
mlischetti Aug 20, 2026
9e1e11e
W-23692110: Release the init reference on abandoned-env teardown (rou…
mlischetti Aug 20, 2026
e839c7c
W-23692110: Document the 1:1 initialize<->engine-bridge assumption (r…
mlischetti Aug 20, 2026
b7784e6
W-23692110: Re-check readiness in runTransform after input pre-buffer…
mlischetti Aug 20, 2026
a26e119
W-23692110: Make engine creation all-or-nothing on cleanup-hook failu…
mlischetti Aug 20, 2026
7ef7547
W-23692110: Fix double-release of init ref in engine-creation hook-fa…
mlischetti Aug 20, 2026
8a038fe
W-23692110: Coalesce overlapping module-level cleanup() calls (round …
mlischetti Aug 20, 2026
d7c4464
W-23692110: Require success for the admitted run-vs-destroy ordering …
mlischetti Aug 20, 2026
6ed316b
W-23692110: Add worker_threads lifecycle integration suite (round 12 #9)
mlischetti Aug 20, 2026
3c7c1dd
Fix module-level cleanup() orphaning a revived singleton; harden term…
mlischetti Aug 20, 2026
5d59364
W-23692110: Add round-13 design spec (per-env init-reference ownershi…
mlischetti Aug 20, 2026
4d69a04
W-23692110: Add per-env init-reference record and helpers (round 13 #…
mlischetti Aug 20, 2026
7660c17
W-23692110: Add bounded isolate_ref_release_n_locked; core release wr…
mlischetti Aug 21, 2026
0963c34
W-23692110: Acquire a per-env init reference in initialize() at all t…
mlischetti Aug 21, 2026
4f19b22
W-23692110: Add env_init_cleanup env-death hook releasing a dead env'…
mlischetti Aug 21, 2026
e67a3d6
W-23692110: Stop the per-engine cleanup hook from releasing the init …
mlischetti Aug 21, 2026
a07358c
W-23692110: Gate cleanup() on the calling env's init-reference owners…
mlischetti Aug 21, 2026
aeb2837
W-23692110: Add per-env init-reference ownership integration tests (r…
mlischetti Aug 21, 2026
714767a
W-23692110: Tear down the just-built isolate on create-path init-reco…
mlischetti Aug 21, 2026
79bf229
W-23692110: Design spec for review #5 remediation (round 14)
mlischetti Aug 21, 2026
d29bb3f
W-23692110: Gate engine creation on ownership + teardown state + op r…
mlischetti Aug 21, 2026
cec5195
W-23692110: Retry stranded teardown so a failed last-release cannot o…
mlischetti Aug 21, 2026
7d68294
W-23692110: Arm the retry signal in release_isolate_ref_locked Case 4…
mlischetti Aug 21, 2026
0b028d3
W-23692110: Release the native init reference even when destroyEngine…
mlischetti Aug 21, 2026
6cc6fd5
W-23692110: Reject every nonzero Worker exit in the test helper (roun…
mlischetti Aug 21, 2026
f76eb39
W-23692110: Add cross-env Worker regression pinning the round-12 over…
mlischetti Aug 21, 2026
d67ae93
W-23692110: Add await dw.cleanup() to resolver quick-start docs (roun…
mlischetti Aug 21, 2026
586e411
docs: add review #6 remediation design spec (round 15)
mlischetti Aug 21, 2026
ceeb66f
chore: stop tracking local scratch docs (review notes + ga-cleanup ba…
mlischetti Aug 21, 2026
18e82fa
fix(node): construct-then-publish module singleton (review #6 #1)
mlischetti Aug 21, 2026
d85a266
fix(node): surface rejected native stream start instead of hanging (r…
mlischetti Aug 21, 2026
827fce1
fix(node): honor graal teardown return code + arm async-waiter strand…
mlischetti Aug 21, 2026
ee92f27
fix(node): complete a stranded teardown from the next initialize() (r…
mlischetti Aug 21, 2026
3e81b48
test(node): surface worker destroy errors + isolate cross-env test st…
mlischetti Aug 21, 2026
15268e1
test(node): assert reinitialization actually re-creates the engine (r…
mlischetti Aug 21, 2026
c68bd3f
docs: review #7 remediation design spec (W-23692110)
mlischetti Aug 24, 2026
789a93f
fix(node): detach the phantom GraalVM thread on a failed teardown (re…
mlischetti Aug 24, 2026
e147c8b
fix(node): arm retry after a failed init-hook rollback so reinit cann…
mlischetti Aug 24, 2026
b7582f3
fix(node): observe the initialize() rollback release and gate reinit …
mlischetti Aug 24, 2026
40e046b
fix(node): track native stream rejection by settlement state, not val…
mlischetti Aug 24, 2026
c6b56b3
test(node): fail worker-lifecycle test when balancing cleanup fails o…
mlischetti Aug 24, 2026
29ef4b9
docs(node): state the final-reference condition in instance cleanup()…
mlischetti Aug 24, 2026
4507caf
docs: update root README Node cleanup examples to await + accurate ho…
mlischetti Aug 24, 2026
ceae7c8
docs(node): correct the #2 retry comment — transient-only recovery, n…
mlischetti Aug 24, 2026
c3e803b
fix(node): fail deterministically instead of deadlocking after a stra…
mlischetti Aug 24, 2026
13f636e
fix(node): survive a synchronous rollback ffi.cleanup() throw in init…
mlischetti Aug 24, 2026
377d478
test(node): always release the native init reference when destroyEngi…
mlischetti Aug 24, 2026
c9bbd12
docs(node): capture streaming terminal metadata via manual next() ite…
mlischetti Aug 24, 2026
76acdf1
docs(node): correct runTransform input-streaming memory claims (async…
mlischetti Aug 25, 2026
e406fe2
docs(node): show required cleanup() in resolver examples (review #8 #6)
mlischetti Aug 25, 2026
8c8a910
docs: qualify root README cleanup drain as final-reference-only (revi…
mlischetti Aug 25, 2026
a52b433
test(node): suppress balancing cleanup error too when the worker-life…
mlischetti Aug 25, 2026
924cedb
docs(node): soften Streaming Large Files bounded-memory claim (readFi…
mlischetti Aug 25, 2026
9bda0da
test(node): assert re-init actually re-invokes createEngine, not the …
mlischetti Aug 25, 2026
fea19cf
test(node): retain and await the resolver cleanup-race promise in try…
mlischetti Aug 25, 2026
2774466
test(node): surface instance-lifecycle cleanup() failures when the te…
mlischetti Aug 25, 2026
81c1842
test(node): assert Worker references were released via the not-initia…
mlischetti Aug 25, 2026
b2c3d3f
fix(node): reject non-null non-string inputCharset at the transform b…
mlischetti Aug 25, 2026
3203d93
docs(node): fix invalid import-before-%dw headers, sync-run blocking …
mlischetti Aug 25, 2026
19a3ea6
docs: consolidate multi-engine design into single final-state doc
mlischetti Aug 25, 2026
0b7714e
docs(specs): unify Node & Python on one handle-based engine model, re…
mlischetti Aug 26, 2026
1f96418
refactor(native-lib): remove ScriptRuntime singleton and legacy C ent…
mlischetti Aug 26, 2026
ffc3231
feat(python): add ctx argument to RESOLVE_MODULE_CALLBACK for per-eng…
mlischetti Aug 26, 2026
2832fea
feat(python): shared refcounted isolate with handle-addressed engines…
mlischetti Aug 26, 2026
7e3ef9a
fix(python): route engine create/destroy through per-OS-thread isolat…
mlischetti Aug 26, 2026
731ec38
feat(python): per-engine resolver ctx trampoline with owner-thread fa…
mlischetti Aug 26, 2026
e4ab709
feat(python): route DataWeave execution through the engine handle; re…
mlischetti Aug 26, 2026
b8ad180
test(python): multi-instance refcount teardown regression (W-23692110)
mlischetti Aug 26, 2026
a9b6c9d
refactor(node): remove legacy run_script path; engine ABI only (W-236…
mlischetti Aug 26, 2026
2cfeda3
docs: correct Python notes + add shared engine-lifecycle contract (W-…
mlischetti Aug 26, 2026
056b5a5
fix(python): detach isolate bootstrap thread + attach-on-demand so cr…
mlischetti Aug 26, 2026
1d996e6
docs: align teardown-failure + Python-isolation notes with the shippe…
mlischetti Aug 26, 2026
ee802eb
docs: consolidate Node + Python multi-engine designs into one spec
mlischetti Aug 26, 2026
089e611
refactor(native-lib): add no-arg ScriptRuntime constructor for built-…
mlischetti Aug 27, 2026
a984dd2
test(node): assert throwing-resolver run() surfaces an error message
mlischetti Aug 27, 2026
ea6b1ca
fix(python): roll back resolver token when _acquire_isolate fails dur…
mlischetti Aug 27, 2026
0c53f99
fix(python): retain live isolate and retry on failed teardown instead…
mlischetti Aug 27, 2026
1130a39
test(python): reset _teardown_needed and _lib_path in unit conftest's…
mlischetti Aug 27, 2026
94e50c6
fix(python): tear down just-created isolate on bootstrap-detach failu…
mlischetti Aug 27, 2026
450a04e
fix(python): make resolver-backed DataWeave.initialize() idempotent (…
mlischetti Aug 27, 2026
ce67fd0
fix(python): serialize per-instance initialize()/cleanup() to prevent…
mlischetti Aug 27, 2026
4389613
fix(node): retain engine bridge when destroy is skipped on attach fai…
mlischetti Aug 27, 2026
545cba7
fix(node): pre-allocate streaming/transform completion sentinel so OO…
mlischetti Aug 27, 2026
dca0569
fix(node): validate raw napi_initialize lib-path argument (review #10…
mlischetti Aug 27, 2026
973e846
fix(node): guard unknown/torn-down handle cleanup against attaching a…
mlischetti Aug 27, 2026
4878824
fix(java): cancel-then-join transform feeder before returning so a sl…
mlischetti Aug 27, 2026
e6bc5cd
test(node): mark only the TCK output-equality assertion as expected-f…
mlischetti Aug 27, 2026
3bd1ff1
test(node): recategorize 6 execution-failure TCK cases from output-mi…
mlischetti Aug 27, 2026
0bb15f9
test(node): fail the dedicated TCK job when the corpus is absent/empt…
mlischetti Aug 27, 2026
95a7d1b
ci(node): require a staged TCK corpus on the dedicated master TCK lan…
mlischetti Aug 27, 2026
24f86dc
docs: document custom-module resolution scope (run() only) and record…
mlischetti Aug 27, 2026
a743697
test(node): sync tck-policy counts to recategorized ignore-list (38/1…
mlischetti Aug 28, 2026
604f39c
test(node): record empirically-verified execution-failure evidence fo…
mlischetti Aug 28, 2026
e66359a
fix(native-lib): close input session and convert exceptions to error …
mlischetti Aug 28, 2026
7bc1a79
fix(native-lib): reject out-of-range input callback lengths instead o…
mlischetti Aug 28, 2026
98be651
fix(python): detach teardown worker on failed isolate teardown so cro…
mlischetti Aug 28, 2026
1ef900f
fix(python): guard module-level global engine creation/cleanup with a…
mlischetti Aug 28, 2026
c4f3f4a
fix(native-lib): fail closed on malformed input JSON instead of execu…
mlischetti Aug 28, 2026
ca2c28a
test(tck): run known execution failures as strict expected failures i…
mlischetti Aug 28, 2026
feb8474
test(tck): table-driven policy checks for expected-execution-failure …
mlischetti Aug 28, 2026
0450b4f
docs(native-lib): correct feeder-error read comment to state the vola…
mlischetti Aug 28, 2026
cb281a3
fix(native-lib): join input feeder before reading its terminal error …
mlischetti Aug 28, 2026
7b79b1c
test(native-lib): add regression guard for join-before-getError order…
mlischetti Aug 28, 2026
d4302bd
fix(python): serialize resolver install and engine init under a per-i…
mlischetti Aug 28, 2026
d93b89c
fix(node): keep the owner-env cleanup hook for stranded resolver brid…
mlischetti Aug 28, 2026
f863620
fix(node): remove the env cleanup hook on the destroyEngine defer pat…
mlischetti Aug 28, 2026
711b2f3
test(node): replace crashing terminate-mid-flight regression with hon…
mlischetti Aug 28, 2026
13866f7
fix(python): retain the bootstrap thread on double-failure so teardow…
mlischetti Aug 28, 2026
d1bc834
docs(native-lib): correct stale isolate-lifecycle and run_script ABI …
mlischetti Aug 28, 2026
8c0d06d
test(python): update README lifecycle guard to the corrected shared-i…
mlischetti Aug 28, 2026
8d1419f
fix(native-lib): remediate review #14 — test hermeticity + lifecycle …
mlischetti Aug 31, 2026
ff483d3
fix(python): stop reusing the bootstrap IsolateThread across OS threa…
mlischetti Aug 31, 2026
88e7b5c
fix(native-lib): stop feeder-join busy-spin when the cleanup caller i…
mlischetti Aug 31, 2026
06ff5a6
docs(spec): align §10 Python teardown-failure behavior with retained/…
mlischetti Aug 31, 2026
95ef4ba
test(native-lib): fix feeder late-failure tests racing their own canc…
mlischetti Aug 31, 2026
0175089
fix(native-lib): treat a -1 read-callback status as a terminal feeder…
mlischetti Aug 31, 2026
07c4841
fix(python): leak-and-continue when teardown recovery cannot detach i…
mlischetti Aug 31, 2026
357e057
docs(spec): redefine the refcount invariant; document the zero-count …
mlischetti Aug 31, 2026
1b0162f
docs(python): correct the stale refcount/isolate invariant in native.…
mlischetti Aug 31, 2026
890db70
fix(node): leak-and-continue on the teardown-plus-detach double failu…
mlischetti Aug 31, 2026
dcff255
docs(node): refresh a stale torn_down comment left after the CLEANUP_…
mlischetti Aug 31, 2026
b6ef969
docs(spec): correct the over-claim that Python needs none of Node's r…
mlischetti Aug 31, 2026
696b8be
docs(native-lib): document the unrecoverable teardown-plus-detach lea…
mlischetti Aug 31, 2026
26679e1
docs(resolver): mark the stale Python resolver design superseded (rev…
mlischetti Aug 31, 2026
c1caecb
docs(spec): document the Node unrecoverable teardown-leak branch in §…
mlischetti Aug 31, 2026
b063811
docs(native-lib): make the ordinary-teardown-failure retry trigger bi…
mlischetti Aug 31, 2026
c8dff29
docs(node): clarify cleanup() guarantees the teardown attempt, not ph…
mlischetti Aug 31, 2026
2414471
docs(native-lib): correct cleanup() to state a teardown attempt, not …
mlischetti Aug 31, 2026
15f5302
docs(spec): mark 2026-08-04 Node external-modules design superseded (…
mlischetti Aug 31, 2026
9064176
docs(node): fix stale lifecycle comments and dead report refs (review…
mlischetti Aug 31, 2026
ae2d908
fix(node): fail init if bootstrap detach fails instead of publishing …
mlischetti Aug 31, 2026
bfdbdd7
fix(node): detach teardown-waiter threads so their OS handles are rec…
mlischetti Aug 31, 2026
08faf6a
fix(node): require graal detach/teardown symbols so the bootstrap-det…
mlischetti Aug 31, 2026
cbd1c86
docs(spec): fix resolver arg order and teardown-completion overpromis…
mlischetti Sep 1, 2026
094677a
fix(node): require graal_attach_thread symbol so a lib missing it fai…
mlischetti Sep 1, 2026
b21efe1
fix(node): poison the isolate on an ordinary detach failure so teardo…
mlischetti Sep 1, 2026
70090ac
test(native-lib): release busy-spin test resources in finally and ski…
mlischetti Sep 1, 2026
141fad7
test(native-lib): comment why ft/feederThread are two variables (revi…
mlischetti Sep 1, 2026
566c701
fix(node): poison on the OOM-rollback detach in napi_create_engine to…
mlischetti Sep 1, 2026
6661b96
test(node): align ca09d69 addon-path test ffi mock with the multi-eng…
mlischetti Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/actions/node/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ runs:

- name: Run Node.js TCK Conformance
if: always() && inputs.run-tck == 'true'
# This is the dedicated (master-only) TCK lane. The corpus is staged once
# by the shared TCK staging step earlier in the job (see main.yml). Set the
# require-corpus flag so a missing/empty staged corpus fails this job loudly
# instead of skipping silently (review #10 #7); local dev without the flag
# still skips.
env:
DATAWEAVE_TCK_REQUIRE_CORPUS: '1'
run: |
cd native-lib/node && npm run test:tck
shell: bash
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,8 @@ grimoires/
# Superpowers implementation plans are local scratch artifacts, never commit them.
/docs/superpowers/plans/
/docs/superpowers/plans/**/*.md

# PR follow-up code-review notes are local scratch, keep them untracked.
/docs/pr-*-follow-up-*code-review*.md
# GA cleanup backlog is a local working note, keep it untracked.
/docs/ga-cleanup-backlog.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
# Design: External DataWeave Module Support in Node.js Binding

**Date:** 2026-08-04
**Status:** Approved for implementation
**Status:** Superseded
**Related Proposal:** [docs/proposals/nodejs-external-modules.md](../../proposals/nodejs-external-modules.md)

> **⚠️ Superseded (2026-08-31).** This document describes the original
> single-resolver Node external-module design. It is retained for historical
> context only. The shipped design is
> [`2026-08-07-native-lib-multi-engine-design.md`](2026-08-07-native-lib-multi-engine-design.md).
> The following assertions below are stale and no longer accurate:
> - **Resolver scope.** A custom resolver does *not* apply to all three
> execution APIs. It resolves custom modules only for `run()`; `runStreaming()`
> and `runTransform()` execute on a background worker that must not call back
> into the resolver, so custom-module imports there fail closed (report the
> module as not found) rather than routing to the callback. Built-in modules
> still resolve everywhere.
> - **One resolver per process.** Resolvers are no longer process-global. Each
> `DataWeave` instance owns its own handle-addressed engine with its own
> resolver; multiple independent resolver-backed engines can coexist in one
> process (each bound to the thread that created it).
> - **Resolver ABI and lifecycle.** The old process-wide resolver ABI is
> replaced by the handle-based `create_engine_with_resolver` + `run_script_engine`
> ABI; a resolver is bound at engine creation and released with that engine's
> `cleanup()`, not installed process-wide.

## Goal

Enable Node.js applications to use external DataWeave modules (reusable libraries) that are not compiled into the native image. Scripts can import modules from directories, JAR files, or in-memory maps, composed with fallback chains.
Expand Down
786 changes: 786 additions & 0 deletions docs/superpowers/specs/2026-08-07-native-lib-multi-engine-design.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@
**Module:** `native-lib` Python binding
**Related implementation:** Node external-module support in PR #154

> **⚠️ Superseded (2026-08-31).** This document describes an early Python-only
> resolver design that PR #157 did not implement. It is retained for historical
> context only. The shipped design is
> [`2026-08-07-native-lib-multi-engine-design.md`](2026-08-07-native-lib-multi-engine-design.md).
> The following assertions below are stale and no longer accurate:
> - `dwlib` no longer exports `run_script_with_resolver`; resolver-backed
> execution goes through the handle-based `create_engine_with_resolver` +
> `run_script_engine` ABI.
> - The feature *did* require Java and native-image changes (the shared engine
> layer), not "no Java/Node changes."
> - There are no dedicated per-instance Python isolates; all `DataWeave`
> instances share one process-wide isolate, addressed by opaque handles.
> - The resolver is bound at `DataWeave.initialize()` (via
> `create_engine_with_resolver`), not installed on the first `run()`.

## Problem

The Python binding cannot resolve reusable DataWeave modules supplied by an
Expand Down
83 changes: 70 additions & 13 deletions native-lib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,52 @@ The main purpose is to allow non-JVM consumers (most notably the Python package
│ ┌────────────────────────────────────────┐ │
│ │ Native Shared Library (dwlib) │ │
│ │ ┌──────────────────────────────────┐ │ │
│ │ │ GraalVM Isolate │ │ │
│ │ │ - NativeLib.run_script() │ │ │
│ │ │ GraalVM Isolate (process-wide) │ │ │
│ │ │ - create_engine / │ │ │
│ │ │ create_engine_with_resolver │ │ │
│ │ │ - run_script_engine / │ │ │
│ │ │ run_script_callback_engine / │ │ │
│ │ │ run_script_input_output_ │ │ │
│ │ │ callback_engine │ │ │
│ │ │ - destroy_engine │ │ │
│ │ │ - DataWeave script execution │ │ │
│ │ └──────────────────────────────────┘ │ │
│ └────────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
```

Each engine is a handle-addressed object created with `create_engine` (or
`create_engine_with_resolver`, which additionally registers a module-resolve
callback) and run via `run_script_engine`, `run_script_callback_engine`, or
`run_script_input_output_callback_engine`, then released with `destroy_engine`.

**Raw C ABI (caller-managed isolate).** At the C level the isolate lifecycle is
the caller's responsibility. A direct consumer creates and attaches the GraalVM
isolate itself via `graal_create_isolate` / `graal_attach_thread`, creates and
destroys any number of engines within it (`create_engine` /
`create_engine_with_resolver` … `destroy_engine`), and tears the isolate down
with `graal_tear_down_isolate` when done. `destroy_engine` only unregisters that
engine from the runtime; it never tears down the isolate. There is no built-in
reference counting at the ABI — the C consumer decides when the isolate is no
longer needed.

**Node / Python bindings (reference-counted isolate).** The bindings layer this
policy on top of the raw ABI: each maintains a single process-wide GraalVM
isolate, reference-counted by the number of live engines across all instances.
The isolate is created and attached on first use and torn down via
`graal_tear_down_isolate` only after the final engine in the process has been
released. Teardown failure has two contracts. An **ordinary** failure (teardown
fails but the worker thread detaches cleanly) retains the live isolate and
retries teardown later, with a binding-specific trigger: **Node** retries at the
next initialization or when an in-flight operation finishes draining (async
op-completion); **Python** retries synchronously at the next initialization. A
**teardown-plus-detach double failure** (in Python, also a bootstrap
detach-plus-teardown double failure) is treated as **unrecoverable** — the
binding resets its published state, emits a diagnostic, deliberately leaks the
isolate for the process lifetime, and lets a future initialization build a fresh
isolate. This ref-counting and teardown policy lives in the binding code, not in
the dwlib engine ABI.

## Building with Gradle

### Prerequisites
Expand Down Expand Up @@ -458,14 +496,24 @@ import { DataWeave } from "dataweave-native";

const dw = new DataWeave();
dw.initialize();

const r1 = dw.run("2 + 2");
const r2 = dw.run("x + y", { x: 10, y: 32 });

console.log(r1.getString()); // "4"
console.log(r2.getString()); // "42"

dw.cleanup();
try {
const r1 = dw.run("2 + 2");
const r2 = dw.run("x + y", { x: 10, y: 32 });

console.log(r1.getString()); // "4"
console.log(r2.getString()); // "42"
} finally {
// cleanup() returns a Promise; await it. When this releases the FINAL shared
// native reference in the process, it drains any in-flight streaming/transform
// op, attempts isolate teardown, and resolves once that attempt completes --
// guaranteeing logical release, not necessarily physical reclamation: an
// ordinary teardown failure retains the live isolate and retries where safe,
// and an unrecoverable teardown-plus-detach double failure intentionally
// leaks it until process exit (with a diagnostic on stderr). When other
// initialized instances remain, it resolves as soon as this instance is
// released, leaving the shared isolate live for them.
await dw.cleanup();
}
```

### 5) Error handling
Expand Down Expand Up @@ -643,11 +691,20 @@ for await (const chunk of gen) {

### 9) Cleanup

The module registers a `process.on('exit')` handler to clean up automatically. For explicit control:
The module registers two process hooks to clean up automatically: `beforeExit`
(async — it awaits cleanup so an in-flight streaming/transform op drains before
the process exits normally) and `exit` (a synchronous best-effort fallback for
`process.exit()` and uncaught exceptions, which cannot await the drain). Neither
hook fires on `SIGTERM`/`SIGINT`/`SIGKILL`, so install your own signal handler
that awaits `cleanup()` if you need a graceful drain on termination. For explicit
control:

```typescript
import { cleanup } from "dataweave-native";

// When done with all DataWeave operations
cleanup();
// When done with all DataWeave operations. cleanup() returns a Promise; await it.
// Draining in-flight streaming/transform work and tearing down the isolate happen
// only when this releases the final shared native reference; if other initialized
// instances remain, it resolves as soon as this instance is released.
await cleanup();
```
Loading
Loading