docs/waves/engine_debug_connector_research.md
Engine Debug Connector Research Notes
Status: reference
Owner lane: engine-wasm + browser
Last reviewed: 2026-03-14
Purpose
Capture external debugger architecture patterns relevant to Waves so D0 implementation work can borrow proven ideas instead of inventing a bespoke inspection model from scratch.
This document complements, but does not replace, docs/waves/ENGINE_DEBUG_CONNECTOR_PLAN.md.
Current Waves Baseline
Current local architecture already provides some useful starting points:
- Tauri host owns a single in-process
WmlEngineinstance behindMutex<WmlEngine>. - Host commands already expose deterministic read-only runtime snapshots after each command.
- Engine already has lightweight trace capture for harness/debug workflows.
- Existing trace support is useful scaffolding, but it is not yet an attachable debugger protocol.
Relevant files:
browser/src-tauri/src/engine_bridge/engine_adapter.rsbrowser/src-tauri/src/contract_types.rsengine-wasm/contracts/wml-engine.tsengine-wasm/engine/src/engine_runtime_internal/trace.rs
Research Goal
Identify debugger and inspector designs from mature systems that resemble Waves in at least one key way:
- embedded runtime inspected through a host process
- structured event/state inspection
- attachable sessions or targets
- optional first-party UI layered on top of a protocol or bridge
Reviewed Systems
1. Chrome DevTools Protocol (CDP)
References:
- https://chromedevtools.github.io/devtools-protocol/
- https://chromium.googlesource.com/chromium/src/+/refs/heads/main/third_party/blink/public/devtools_protocol/README.md
Why it matters:
- CDP is a strong reference for typed command/event protocols over a host boundary.
- It separates runtime instrumentation from the inspector frontend.
- It treats attach, enable, and target/session concepts as explicit protocol elements.
Patterns worth borrowing:
- group debugging features into additive typed surfaces instead of one catch-all blob
- use stable string identifiers and event names
- require explicit client opt-in before streaming heavier event traffic
- keep commands/events protocol-oriented rather than UI-oriented
Notable caution:
- CDP is much broader than Waves needs; copying its domain sprawl would be counterproductive.
2. Firefox Remote Debugging Protocol (RDP)
Reference:
Why it matters:
- RDP shows a clean attachable lifecycle with explicit actor ownership and teardown.
- It models request/reply and notification traffic cleanly.
- It is a good example of inspection over a brokered runtime boundary.
Patterns worth borrowing:
- make resource/session lifetime explicit
- allow read-only notifications without making the runtime depend on an always-live client
- keep parent/child ownership clear between broker and inspected runtime
Notable caution:
- Actor-model machinery would be excessive for the first Waves implementation.
3. VS Code Debug Adapter Protocol (DAP)
References:
- https://microsoft.github.io/debug-adapter-protocol/
- https://code.visualstudio.com/api/extension-guides/debugger-extension
Why it matters:
- DAP is the clearest precedent for separating debugger UI from runtime-specific debugging logic.
- The adapter sits between generic tooling and the actual runtime/debugger.
- It proves the value of a host-owned translation layer.
Patterns worth borrowing:
- keep the host bridge as an adapter, not as the runtime itself
- keep the frontend consumer reusable by depending on typed host contracts
- advertise capabilities up front so clients can adapt to partial support
Notable caution:
- DAP assumes a richer command model than Waves needs in MVP; Waves should stay read-only.
4. Node Inspector
Reference:
Why it matters:
- Node is a strong precedent for local attach, session URLs/ids, and secure-by-default warnings.
- It treats debugger access as privileged.
Patterns worth borrowing:
- default to local-only debugging surfaces
- disable or omit the connector outside development profiles by default
- make attachability a deliberate act, not ambient behavior
Notable caution:
- Waves should avoid exposing a network-listening inspector in MVP.
5. WebKit Remote Inspection
Reference:
Why it matters:
- WebKit shows how an embedded runtime can remain inspectable without mixing inspector logic into app UI logic.
- It reinforces the value of a host-managed inspection surface for embedded contexts.
Patterns worth borrowing:
- make the runtime inspectable through a host boundary
- preserve runtime semantics even when inspection is attached
- keep the inspector out of the core execution path
6. Redux DevTools / Remote Redux DevTools
References:
Why it matters:
- It is a practical example of structured state/action history, export, replay-oriented artifacts, and an optional remote monitor.
- It is closer to Waves than a full debugger when thinking about timeline inspection and bug triage.
Patterns worth borrowing:
- keep event history structured and exportable
- support an in-app first-party monitor first
- treat remote monitoring as optional and additive
Notable caution:
- Waves is runtime inspection, not just state history; event payloads still need runtime-specific design.
Repeated Patterns Across Mature Systems
These themes appeared consistently across the systems above:
- Separate runtime semantics from debugger transport and UI.
- Model debugging as attachable sessions or targets.
- Use structured, typed events and snapshots instead of free-form logs.
- Gate heavier inspection behind explicit attach/enable.
- Keep debugging additive and non-disruptive to normal runtime behavior.
- Prefer local/dev-only exposure for privileged debugging surfaces.
- Use stable string ids and event names.
- Preserve determinism even if the debugger is disconnected, slow, or absent.
Recommended Waves Architecture
Based on repo constraints and the systems reviewed above, Waves should use a three-layer debug connector:
Layer 1: Engine-owned recorder
Location:
engine-wasm/engine
Responsibilities:
- deterministic event emission at runtime boundaries
- fixed-size ring buffer with drop-oldest behavior
- monotonic sequence numbering
- read-only debug snapshot generation
- sensitive-field masking before data leaves engine-owned structures
Non-responsibilities:
- no host IPC
- no session bookkeeping
- no UI-specific formatting
Layer 2: Host-owned session broker
Location:
browser/src-tauribrowser/contracts/*
Responsibilities:
- debug session open/close lifecycle
- local policy gating and dev-mode enablement
- command validation and error handling
- mapping engine debug types to generated Rust/TypeScript contracts
- optional later expansion to external tooling surfaces
Non-responsibilities:
- no reinterpretation of engine runtime semantics
- no mutation/debugger control plane in MVP
Layer 3: Consumer UI/tooling
Location:
browser/frontend- possible later external tool bridge
Responsibilities:
- polling recent events
- rendering timeline and snapshot views
- export-to-JSON capture flow
- filtering/search/presets
Non-responsibilities:
- no direct runtime mutation
- no source of truth for masking or sequencing
Recommended MVP Contract Style
The current plan direction is correct. The preferred additive surface is:
openDebugSession(options) -> { sessionId, cursor, capabilities }pollDebugEvents({ sessionId, cursor, maxEvents }) -> { events, nextCursor, droppedCount }getDebugSnapshot({ sessionId }) -> EngineDebugSnapshotcloseDebugSession({ sessionId }) -> { closed: boolean }
Recommended notes:
sessionIdshould be host-owned, process-local, and opaque- engine should expose cursor-based polling primitives, but should not own per-client sessions
capabilitiesshould be explicit so clients can adapt safely
Suggested initial capabilities:
supportsSnapshots: truesupportsPolling: truemasking: "masked"supportsUnmaskSensitive: false
Polling vs Push
Recommendation: use polling for MVP.
Why:
- simpler host/runtime integration
- easier deterministic testing
- avoids background event pump complexity in Tauri
- works for both native host integration and future WASM-boundary use
- failure in the consumer does not pressure the engine execution path
Suggested behavior:
- consumer polls only while debug panel/tool is open
- host or UI can use a bounded interval such as
100-250ms - event delivery remains best-effort within the ring-buffer window
Event Ordering and Time
Recommendation:
seqis the primary ordering keytsMsis useful for operator context, but not for correctness- snapshots and replay-oriented tooling should trust
seq, not wall clock
Reasoning:
- deterministic runtime ordering is more important than wall-clock precision
- monotonic sequence values are stable across local triage and tests
Session Ownership
Recommendation:
- host owns sessions
- engine owns event history and snapshot generation
Why:
- the engine currently models one running runtime, not a debugger multiplexer
- host-managed sessions make future multi-client support additive
- this preserves clean boundaries between runtime semantics and IPC/lifecycle concerns
Sensitive Data Policy
Recommendation:
- mask sensitive values at the engine boundary
- keep local unmasking off by default
- avoid exposing raw transport credentials or secrets in events or snapshots
Suggested sensitive-field heuristics for MVP:
- password-type inputs
- field names including
pin,passwd,password - runtime vars derived from masked fields
Reasoning:
- frontend-only masking is too easy to bypass accidentally
- engine-side masking gives consistent behavior across all consumers
Recommended Event Set for Waves MVP
The event list in the current plan remains sound:
deck.loadcard.entercard.exitfocus.changeinput.edit.startinput.edit.draftinput.edit.commitinput.edit.cancelaction.acceptaction.externalnav.intentpostfield.resolvescript.invokescript.traptimer.scheduletimer.firetimer.cancel
Strong recommendation:
postfield.resolveshould include resolution source per field:vardraftcardfallback
This is the single highest-value event detail for form-submit triage.
Recommended Snapshot Contents
The snapshot should cover enough state to explain the latest behavior without requiring a full memory dump.
Recommended MVP snapshot:
- active card id
- focused link index
- focused input edit name/value with masking applied
- runtime vars with masking applied
- active card form-state summary
- pending external navigation intent
- pending external navigation request policy including post context
- timer state summary
- debug buffer metadata:
oldestSeq,latestSeq,droppedCount - viewport cols
- base URL
- content type
Relationship to Existing traceEntries()
Current trace support is useful, but it should not become the long-term debug connector contract.
Recommended stance:
- treat
traceEntries()as legacy harness/debug support - reuse trace learnings and some emission points where practical
- move D0 work onto typed events/snapshots rather than extending string-detail traces indefinitely
Reasoning:
- traces are useful for humans, but weak as a stable contract
- typed events will age better for host/frontend/test consumers
Recommended MVP Delivery Strategy
The best first usable setup is:
- engine-owned ring buffer and snapshot builder
- Tauri-host debug session commands
- Waves first-party debug panel
- JSON export for bug artifacts
Do not start with:
- remote networked debugger transport
- mutable debugger commands
- full external IDE/tool integration
Reasoning:
- the in-app panel is the fastest path to real debugging value
- it exercises the right contracts without forcing protocol or security complexity too early
- external tooling can be added later on the same host-backed API
Proposed Reference Model for Waves
If Waves borrows selectively from mature systems, the best blend is:
- CDP for protocol shape and typed event surfaces
- DAP for layered architecture and host-adapter thinking
- Firefox RDP for attach/detach lifecycle clarity
- Node inspector and WebKit for dev-only/local safety posture
- Redux DevTools for timeline/export workflow ideas
This mix fits Waves better than copying any single ecosystem whole.
Guidance for D0 Work Items
D0-01 Contract and architecture baseline
Focus:
- additive contract types only
- explicit session lifecycle
- capabilities and masking policy
- no runtime event emission yet
D0-02 Engine event stream and snapshot emitter
Focus:
- fixed-size event ring buffer
- deterministic event ordering and drop accounting
- engine-side masking
- no host/UI concerns in engine implementation
D0-03 Host bridge integration
Focus:
- Tauri commands for open/poll/snapshot/close
- deterministic error handling
- contract generation for frontend clients
D0-04 Browser debug panel
Focus:
- optional read-only panel
- bounded polling while visible
- export-to-JSON bug artifact workflow
Decisions Recommended Before Implementation
These should be settled in D0-01 before code lands:
- event timestamps: monotonic only vs monotonic plus optional wall-clock projection
- default ring-buffer size in dev and CI contexts
- whether MVP supports more than one concurrent session
- exact masking heuristics for WML input names/types
- exact
postfield.resolvepayload schema
Bottom Line
The strongest proven pattern for Waves is:
- engine-owned recorder
- host-owned sessions
- read-only polling contract
- engine-side masking
- first-party Waves panel first
- external debugger/tool bridge later, reusing the same host-backed API
That gives Waves a practical runtime debugger without violating current layer boundaries or overcommitting to a remote-debug protocol too early.