ESD-1584-docs(wasm): document interactive-mode host contract#486
ESD-1584-docs(wasm): document interactive-mode host contract#486Phil-Browne wants to merge 15 commits into
Conversation
Document the WASM interactive-mode host contract (async-only requirement, registerPromptHandler/submitPromptResponse/cancelPrompt, prompt-request shape, and password masking) in WASM_README.md and the frontend INTEGRATION_GUIDE.md. Guard the legacy synchronous executeMegaportCommand entrypoint: a command that requests a prompt while running under it now returns a clear error instead of deadlocking the JS event loop. Extend interactive.test.ts with password-masking, cancel, and async-only assertions, and add a Go test for the sync-path guard. ESD-1584
- Reconcile docs/CHANGELOG with actual behavior: value prompts return the
guard error, but confirmations are treated as declined (wasmConfirmPrompt
swallows the error to false), so the sync entrypoint no longer deadlocks
either way.
- Fix cancel error string in docs to match code ("prompt cancelled by user").
- Add "password" to the PromptType field comment; note the guard counter is
process-global and fails safe.
- Drop the tautological secret-resource TS test that only asserted its own
fixture.
Some secret-bearing inputs (partner auth/service/shared keys, MVE registration/secret keys) are prompted as type "resource", not "password". Drop the inaccurate "covers every secret" claim and tell integrators not to rely on the password type alone to mask every secret. Note secret-resource prompts also carry a resourceType.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #486 +/- ##
==========================================
+ Coverage 77.96% 78.54% +0.58%
==========================================
Files 192 192
Lines 18391 18507 +116
==========================================
+ Hits 14339 14537 +198
+ Misses 2989 2904 -85
- Partials 1063 1066 +3 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR documents the browser/WASM interactive-mode host contract (prompt callback lifecycle and prompt request shape) and adds a guard so the legacy synchronous WASM entrypoint no longer deadlocks the browser event loop when a command tries to prompt.
Changes:
- Documented the interactive-mode JS host contract and clarified that interactive commands must use the async entrypoint.
- Added a sync-entrypoint guard (tracking sync execution depth) so value prompts fail fast with a clear error instead of hanging.
- Extended WASM (Go) and frontend integration (Vitest) tests to cover async-only behavior, cancel lifecycle, and password-masking expectations.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
WASM_README.md |
Documents the interactive-mode host contract and async-only requirement. |
frontend-integration/INTEGRATION_GUIDE.md |
Adds integration guidance for wiring prompt handlers and using the async entrypoint. |
internal/wasm/prompts.go |
Introduces sync-entrypoint tracking and prompt guard to fail fast under sync execution. |
main_wasm.go |
Marks the legacy sync entrypoint as “sync execution” so prompt requests are rejected instead of deadlocking. |
internal/wasm/prompts_test.go |
Adds coverage for the sync-path prompt guard in Go WASM tests. |
frontend-integration/__tests__/interactive.test.ts |
Adds tests for password masking, cancel behavior, and async-only routing/guard surfacing. |
CHANGELOG.md |
Notes the deadlock fix and documentation updates for WASM interactive mode. |
Clamp EndSyncExecution at 0 with a CAS loop so a stray or duplicate call can't drive the counter negative and re-enable prompting under the sync entrypoint. Reset pendingPrompts and release the JS function wrapper in the sync-guard test to avoid cross-test state leaking. Shorten the hardcoded guard-error string in the frontend test to a stable substring instead of the full message.
Correct INTEGRATION_GUIDE.md: an unregistered prompt handler fails fast, it does not hang (the 5-minute timeout only applies once a handler is registered and a prompt goes unanswered). Unmount the test wrapper before throwing in createReadyComposable so a WASM-not-ready failure doesn't leave a mounted component behind. Restore fetch/WebAssembly/Go globals and the executeMegaportCommand mocks in an afterEach for the Async-Only Entrypoint tests so they can't leak into later tests in the file.
Match the production locking discipline for promptCallback so a future refactor or parallelized test run can't reintroduce a data race on this package-level field.
wasmSecretResourcePrompt sends secret-resource prompts as PromptType "password" while still populating ResourceType, so the field isn't limited to "resource" prompts as the comment implied.
The previous fix polled pendingPrompts for up to 1s, which still had a window where the test could hang if the prompt wasn't registered by then. Respond from the prompt callback itself, using the id it's called with, since PromptForInput always registers the prompt before invoking the callback.
The cur <= 0 branch stored 0 unconditionally, so a concurrent BeginSyncExecution could increment the counter between the load and the store, and this call would clobber it back to 0, incorrectly re-enabling prompting while a sync execution is still in progress. Compute the clamped next value and commit it with the same CAS used for the normal decrement, so a concurrent change always aborts the attempt and retries against the fresh value.
|
QA review — doc/contract accuracy The code change (the sync-execution fast-fail guard) looks good. Two doc items I'd flag before merge, both about the docs matching the actual composable behaviour rather than code defects. 1. The guide says:
But The immediate "prompt callback not registered" failure only applies when driving the raw WASM globals directly (no
2. type: string; // "text", "confirm", "resource"
resourceType?: string; // for resource promptsThis PR adds type: string; // "text" | "confirm" | "password" | "resource"
resourceType?: string; // set for "resource" and secret ("password") promptsItem 1 is the one I'd fix before merge — the whole value of a contract doc is that integrators can trust the failure-mode description. |
The Interactive Commands section claimed a missing handler fails immediately, but useMegaportWASM registers a default no-op handler at init, so composable callers who forget to override it hit the 5-minute timeout instead. Split the two paths: composable (no-op default, hangs to timeout) vs raw WASM globals (immediate 'prompt callback not registered' error). Also bring the MegaportPromptRequest TypeScript definition in step with the Go struct and guide: add 'password' to the type union and note resourceType is set for both resource and secret (password) prompts.
|
Thanks, both fixed in 8b75b1b.
|
Changelog entries are now auto-generated at release time.
|
Both doc items resolved — thanks. Confirmed against
One thing blocking merge, not a code issue: the PR is currently Needs a rebase onto main so CI can run and go green — I'll re-review and approve once it's mergeable. The doc review itself is done. |
…tive-docs-fix # Conflicts: # WASM_README.md # internal/wasm/prompts.go # main_wasm.go
|
Both doc items resolved, thanks. Confirmed against 8b75b1b:
Rebased onto main and resolved conflicts in WASM_README.md, internal/wasm/prompts.go, internal/wasm/prompts_test.go, and main_wasm.go. Note: the rebase surfaced that #492 (merged after this branch diverged) fully retired the synchronous entrypoint, so it no longer just fails fast on prompts, it never runs a command at all. I updated the Interactive Mode doc text (WASM_README.md and INTEGRATION_GUIDE.md) to match that, and dropped the now-dead sync-guard code (syncExecutionDepth, BeginSyncExecution/EndSyncExecution) and its test that this PR had added, since main's retirement supersedes it. CI is running now that the branch is mergeable. Will re-review once it's green. |
|
Doc/code mismatch worth fixing before merge:
Since this PR's whole purpose is documenting the host contract precisely, this is exactly the kind of detail an integrator would build against and get wrong. Otherwise the contract docs check out against the current implementation (composable default handler, resource-vs-secret prompt typing for partner/MVE keys, |
|
Fixed in 7492582. All four spots now say 10 minutes to match |
|
#514 deletes |
|
Closing in favor of #514. We settled on the deletion in #514 as the direction: Nothing unique is lost: the |
Documents the WASM interactive-mode host contract and makes the legacy sync entrypoint fail loudly instead of hanging.
The browser CLI has no stdin, so interactive commands ask the host page for input through JS callbacks. That contract was undocumented, and running an interactive command through the legacy synchronous
executeMegaportCommanddeadlocked the event loop (the host could never deliver a response).What changed:
executeMegaportCommandnow fails fast. Value prompts return a clear "interactive mode requires the async entrypoint" error; confirmations are treated as declined. No more deadlock.WASM_README.mdandfrontend-integration/INTEGRATION_GUIDE.md: async-only requirement,registerPromptHandler/submitPromptResponse/cancelPrompt, the prompt-request shape, and password masking (with a caveat that some secrets currently arrive astype "resource").interactive.test.tswith password-masking, cancel, and async-only assertions, and add a Go test for the sync-path guard.Streamed-output docs are deferred to the live-output-streaming ticket.
Closes ESD-1584.