From a6e8055e70950c57094fb6bbda29441100677929 Mon Sep 17 00:00:00 2001 From: Bruno Carvalho Date: Sun, 21 Jun 2026 23:04:26 -0300 Subject: [PATCH] docs(architecture): client interactivity & communication model plan (#520) Add the epic decomposition for unifying the client interactivity surface (docs/engineering/client-interactivity-model-plan.md): reduce ~10 concepts to ~5 orthogonal primitives, fix the determinism-integrity risk at its root via single-source semantics (#384), and turn the bounded->WASM cliff into a ladder. Captures the target primitive set, the today->target mapping, the #384 gate, the workstream sequencing (#384 -> #517 -> #518/#519), the migration posture, and the decisions already recorded in ADRs 0016 (#519) and 0017 (#518). The epic (#520) remains the open tracker; it closes when its workstreams land. --- CHANGELOG.md | 5 + .../client-interactivity-model-plan.md | 100 ++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 docs/engineering/client-interactivity-model-plan.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ee38fe2..01db565a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ packages, and tooling contracts may change before 1.0. - The client expression runtime now receives its operator and builtin metadata from the Go compiler/runtime spec instead of hardcoded JavaScript tables, reducing Go/JS drift for generated islands. +- Added the client interactivity & communication model plan + (`docs/engineering/client-interactivity-model-plan.md`): the epic decomposition + that reduces the browser surface to ~5 orthogonal primitives, gated on + single-source semantics (#384) and sequencing scoped state (#517), callback + props (#518), and pure Go helpers (#519). - Docs now use the current `server {}` / `go server {}` server-lane syntax outside changelog/migration/diagnostics contexts, the README addon table lists `observability` and `spa`, and the security-audit docs no longer tie the diff --git a/docs/engineering/client-interactivity-model-plan.md b/docs/engineering/client-interactivity-model-plan.md new file mode 100644 index 00000000..7ff00651 --- /dev/null +++ b/docs/engineering/client-interactivity-model-plan.md @@ -0,0 +1,100 @@ +# Implementation Plan: Unify the Client Interactivity & Communication Model + +## Context + +Epic: `cssbruno/GoWDK#520` + +The browser-side surface has grown to roughly ten loosely-related concepts. This +plan is the architectural decomposition for the epic: reduce that surface to a +small set of orthogonal primitives, close the determinism-integrity risk at its +root, and turn the bounded→WASM cliff into a ladder — without weakening the +"islands not hydration / bounded / Go-owned / deterministic" principles +(ADR 0008, ADR 0003). + +It does not introduce new behavior on its own; it sequences and ties together the +workstream issues and their ADRs so each can land independently in the right +order. + +## Today's surface (~10) + +`state`, `computed`, `effect`, `props`, scoped slots, `emit`, `exports`, +`g:bind`, page stores, app-global stores, instance/context state, realtime. + +The redundancy is concentrated in two places: + +- **State sharing** is expressed three+ ways (page stores, app-global stores, + instance/context state, plus `exports` observation). +- **Parent↔child communication** is expressed three ways (`emit` + `g:on`, + `exports` + `g:on:exports`, `g:bind`) that already lower to one transport. + +## Target (~5 orthogonal primitives) + +1. **Reactive state with a scope axis** — `state @island | @page | @app | @instance`, + one lifecycle and one mental model instead of separate store kinds. → #517 + (supersedes #508, #515). +2. **`computed` / `effect`** — unchanged. +3. **Communication = callback props (actions) + scoped cells (state)**; `bind:` + is sugar. → #518 / ADR 0017. +4. **Scoped slots** — unchanged. +5. **No event bus** — #514 (closed); explicit ownership over implicit coupling. + +Pure Go helpers (#519 / ADR 0016) are the escape hatch that keeps the bounded +language small while removing the cliff — not a sixth primitive, but the ladder +rung between bounded expressions and a full WASM island. + +## Foundational gate: single-source semantics (#384) + +Every client-language expansion in this epic is **gated on #384** — one IR and one +evaluator that generate *both* the validator and the runtime, so there is a single +source of truth for client semantics. The pattern already exists in the +`RuntimeExpressionSpec` that drives operator/builtin parity (and is cross-checked +by the expression conformance test). #384 generalizes that to the whole bounded +language. Widening the surface (iteration #501, switch/match #504, Go helpers +#519, scoped cells #517) before #384 would multiply the Go/JS divergence surface, +so #384 lands first. + +## Workstreams and sequencing + +1. **#384 — single-source client semantics.** Foundational; gates everything + below. One IR + one evaluator; generate validator AND runtime. +2. **#517 — unify reactive state under `state @scope`.** Collapses page/app/ + instance stores into one scoped primitive (supersedes #508, #515). Unblocks + the state half of #518. +3. **#518 — callback props + scoped cells** (ADR 0017). Action half is + #517-independent and can land right after #384; state half (`bind:` over a + scoped cell) follows #517. +4. **#519 — pure Go helpers from the bounded client** (ADR 0016). Follows #384; + independent of #517/#518. + +Gated on #384 but outside this epic's primitive set: **#501** (iteration) and +**#504** (switch/match) — don't widen the divergence surface before #384. + +## Decisions captured + +- ADR 0008 — bounded client language (the boundary this epic preserves). +- ADR 0016 — pure Go helpers compile to WASM from their Go source (#519). +- ADR 0017 — callback props (actions) + scoped cells (state); `bind:` as sugar; + deprecate `emit`/`exports`/`g:bind` (#518). +- #514 (closed) — no event bus. + +## Migration posture + +Breaking changes are acceptable in 0.x and follow the v0.6.0 lane-rename +precedent: every removed/renamed form gets a precise migration diagnostic, never +a silent alias. Migration notes ship with each workstream's implementing change, +not ahead of it. + +## Out of scope (unaffected by this epic) + +`#502`, `#503`, `#505`, `#506`, `#507`, `#509`, `#510`, `#511`, `#512`. + +## Considered & rejected + +Event bus (#514, closed); full-page hydration; resumability (Qwik-style). + +## Status + +This document is the epic's architectural plan. The epic issue (#520) remains the +open tracker; it closes when its workstreams (#384, #517, #518, #519) land. This +plan and ADRs 0016/0017 capture the decided direction so the workstreams can +proceed in order.