0011-phase4-browser-runtime.md
1 # RFC-0011 — Phase 4 Browser Runtime 2 3 Status: Accepted 4 5 ## Summary 6 7 Implement a minimal browser runtime in `client/lightspeed.js` with: 8 9 - connect/reconnect loop 10 - delegated browser events 11 - patch application 12 - ack protocol behavior 13 - loading/error states 14 - client-side hooks API draft 15 16 ## Motivation 17 18 Phase 3 introduced protocol codec and transport adapters, but no concrete browser runtime consumed that protocol in the DOM. Phase 4 requires a practical client that can mount a live view and maintain reliable patch/event flow. 19 20 ## Design 21 22 ### Runtime API 23 24 Provide: 25 26 - `LightspeedClient` 27 - `mountLightspeed(options)` 28 - `encodeFrame(frame)` and `decodeFrame(payload)` helpers 29 30 Runtime resolves root from `[data-ls-root]` or `#app`, and URL from explicit config or `data-ls-ws`. 31 32 ### Protocol behavior 33 34 - send `hello` frame on socket open 35 - decode incoming frame payloads 36 - apply `diff` frame HTML patches to root 37 - send `ack` after successful patch apply 38 - send `failure` frames on decode/patch errors 39 40 ### Event delegation 41 42 Delegate `click` and `submit` from root to `[data-ls-event]` targets, then send `event` frames with client-generated references. 43 44 ### Reconnect loop 45 46 On non-manual close: 47 48 - transition to `reconnecting` 49 - schedule exponential backoff reconnect 50 - reconnect and re-send `hello` on open 51 52 ### Loading/error state model 53 54 Expose runtime state through root dataset markers: 55 56 - `data-ls-client-state` 57 - `data-ls-loading` 58 - `data-ls-error` 59 60 Emit custom events: 61 62 - `lightspeed:state` 63 - `lightspeed:error` 64 65 ### Hooks API draft 66 67 Support `data-ls-hook` elements with optional callbacks: 68 69 - `mounted` 70 - `updated` 71 - `destroyed` 72 - `disconnected` 73 - `reconnected` 74 75 Hook context includes client handle and `pushEvent`. 76 77 ### Duplicate patch handling 78 79 Duplicate `diff` references are treated idempotently: 80 81 - patch is not re-applied 82 - `ack` is re-sent deterministically 83 84 ## API impact 85 86 Adds browser runtime module API in `client/lightspeed.js`. 87 88 ## Protocol impact 89 90 Consumes existing frame model and codec; no new frame types. 91 92 ## ISA impact 93 94 No ISA changes. 95 96 ## Security impact 97 98 - runtime does not evaluate arbitrary script content from patches 99 - failures are surfaced through explicit protocol failure frames 100 - delegated events require explicit `data-ls-event` markers 101 102 ## Alternatives 103 104 - implement browser runtime in Gleam-to-JS first 105 - postpone hooks until a later phase 106 - use JSON-only browser codec instead of shared delimited codec 107 108 ## Unresolved questions 109 110 - Should reconnect frame include explicit rejoin metadata beyond hello? 111 - Should hook lifecycle include per-event callbacks in Phase 5?