Part of #41. Capability C2. Depends on F1 (#38) + K (incl. async-coloring-into-client) + F2. Related: #31, #35, #36.
Goal
Deliver the React Server Components use client / use server benefit — write data logic once, the framework handles where it runs and the wire between — but generalized:
- the boundary is Ruby class type, not a string directive:
ApplicationController = server, Stimulus::Controller / native client = client, ApplicationRecord = isomorphic;
- the data location (local sqlite-wasm/OPFS / on-device SQLite vs HTTP DB vs
/__rpc) is a deploy-profile decision, not authored;
- reaches client-local (whole backend on-device), which RSC can't.
Existence proof (juntos dictaphone)
The same Clip < ApplicationRecord is used server-side in ClipsController and client-side in a Stimulus controller:
clip = await Clip.create(name:, transcript:, duration:) # AR in the browser
await clip.audio.attach(@audioBlob, ...) # Active Storage, client-side
await clip.broadcast_replace_to("clips") # Turbo Stream, from the client
The await is the tell — client AR call sites are async-colored (K §3). roundhouse must make the compiler derive this and emit the model twice (server-language AR + TS/wasm/Kotlin/Swift client AR) from one Ruby source with a matching contract (the F1/#38 polyglot generalization).
Scope
- Isomorphic model dual-emit (shared, importable; per-tier).
- Transport selection by profile (local DB adapter vs
/__rpc).
- Carry declarative model metadata across the boundary (
validates, has_one_attached, broadcasts_to all run client-side in dictaphone).
THE central decision (folded D — gates this issue)
RPC authorization / exposure boundary: which model operations are client-callable, and how authorized? Client-direct Clip.create bypasses the server's clip_params.permit(...). This is what RSC's 'use server' ceremony exists to guard. Lean server-by-default, client opt-in via a model client / replicated macro.
Open
Local-first sync/conflict when client-local AR later syncs → see #36 (out of v1 scope; name it).
Part of #41. Capability C2. Depends on F1 (#38) + K (incl. async-coloring-into-client) + F2. Related: #31, #35, #36.
Goal
Deliver the React Server Components
use client/use serverbenefit — write data logic once, the framework handles where it runs and the wire between — but generalized:ApplicationController= server,Stimulus::Controller/ native client = client,ApplicationRecord= isomorphic;/__rpc) is a deploy-profile decision, not authored;Existence proof (juntos dictaphone)
The same
Clip < ApplicationRecordis used server-side inClipsControllerand client-side in a Stimulus controller:The
awaitis the tell — client AR call sites are async-colored (K §3). roundhouse must make the compiler derive this and emit the model twice (server-language AR + TS/wasm/Kotlin/Swift client AR) from one Ruby source with a matching contract (the F1/#38 polyglot generalization).Scope
/__rpc).validates,has_one_attached,broadcasts_toall run client-side in dictaphone).THE central decision (folded D — gates this issue)
RPC authorization / exposure boundary: which model operations are client-callable, and how authorized? Client-direct
Clip.createbypasses the server'sclip_params.permit(...). This is what RSC's'use server'ceremony exists to guard. Lean server-by-default, client opt-in via a modelclient/replicatedmacro.Open
Local-first sync/conflict when client-local AR later syncs → see #36 (out of v1 scope; name it).