about summary refs log tree commit diff stats
path: root/js/baba-yaga/scratch/docs/IO.md
diff options
context:
space:
mode:
Diffstat (limited to 'js/baba-yaga/scratch/docs/IO.md')
-rw-r--r--js/baba-yaga/scratch/docs/IO.md198
1 files changed, 198 insertions, 0 deletions
diff --git a/js/baba-yaga/scratch/docs/IO.md b/js/baba-yaga/scratch/docs/IO.md
new file mode 100644
index 0000000..6399b66
--- /dev/null
+++ b/js/baba-yaga/scratch/docs/IO.md
@@ -0,0 +1,198 @@
+# IO Plan: Events and Effects for Baba Yaga
+
+This document proposes an opinionated IO interface for embedding Baba Yaga programs into host systems. We introduce two core primitives for evented IO:
+
+- `io.listen` — subscribe to external events by name
+- `io.emit` — publish events (commands/effects) produced by Baba Yaga
+
+The design follows a TEA/FRP-inspired architecture: a single unidirectional data-flow where external inputs become events, user logic transforms state and produces new effects, and the host executes those effects and feeds results/errors back as new events.
+
+## Goals
+
+- One clean, documented integration path for host systems (Node, browser, services)
+- Pure, testable user code: all side-effects mediated by the host via `io.emit` and `io.listen`
+- Deterministic core: program logic remains a function of prior state and incoming events
+- Easy to build SDKs/harnesses around a small surface area
+
+## Mental Model
+
+```
+External world -> Events -> Baba Yaga Program -> Effects -> Host executes -> more Events
+```
+
+- Events are immutable data records identified by a string `topic` and a payload `data`.
+- Effects are commands (also a `topic` + `data`) that the host is responsible for executing.
+- Round-trips (request/response) are modeled as a pair of topics, e.g. `http.request` and `http.response`.
+
+## Core API (Language-Level Semantics)
+
+The following describes the intended semantics. Implementation comes later.
+
+- `io.listen topic handler` — registers a handler function for events matching `topic`.
+  - `topic : String`
+  - `handler : (event: { topic: String, data: Table }) -> Unit`
+  - Returns `Unit`.
+  - Handlers are pure (no direct side-effects); they may call `io.emit` to request effects.
+
+- `io.emit topic data` — emits an effect (command) to the host.
+  - `topic : String`
+  - `data : Table | List | String | Int | Float | Bool`
+  - Returns `Unit`.
+
+### Event Routing and Namespacing
+
+- Topics use dotted names, e.g. `app.tick`, `db.query`, `ws.message`, `http.request`.
+- Conventionally, effects (commands) and events are separate namespaces; e.g. commands under `cmd.*` and events under `evt.*`, or paired `http.request`/`http.response`.
+
+## Program Structure (TEA-flavored)
+
+We encourage a TEA-like structure:
+
+```baba
+// State is a Table (author’s choice)
+State : type alias Table; // conceptual
+
+// Update: State x Event -> (State, Effects)
+update : (state, event) -> { state: State, effects: List } ->
+  when event.topic is
+    "app.init" then { state: { count: 0 }, effects: [] }
+    "app.tick" then { state: { count: state.count + 1 }, effects: [] }
+    "http.response" then { state: state, effects: [] }
+    _ then { state: state, effects: [] };
+
+// Subscriptions: declare external event interest
+init : ->
+  io.listen "app.tick" (e -> io.emit "cmd.render" { count: 0 });
+
+// Effect producers inside handlers
+handleTick : e -> io.emit "cmd.render" { count: e.data.count };
+```
+
+Notes:
+- `io.listen` is declarative; the host wires it to real sources.
+- Handlers do not perform side-effects directly but may `io.emit` effects.
+
+## Host SDK / Harness
+
+The host must implement a small, stable interface to embed and drive programs.
+
+Suggested host-side API (pseudo-TypeScript):
+
+```ts
+type Event = { topic: string; data: unknown };
+type Effect = { topic: string; data: unknown };
+
+interface BabaProgram {
+  // Run a program to completion on an input source; returns a controller
+  start(initialEvents?: Event[]): ProgramController;
+}
+
+interface ProgramController {
+  // Push an external event into the program
+  dispatch(event: Event): void;
+  // Subscribe to effects emitted by the program
+  onEffect(subscriber: (effect: Effect) => void): () => void; // unsubscribe
+  // Stop the program and cleanup
+  stop(): void;
+}
+
+interface HostIO {
+  // Wire program-level io.listen registrations to host event sources
+  addListener(topic: string, handler: (event: Event) => void): () => void; // unsubscribe
+  // Deliver effects to the host for execution
+  deliver(effect: Effect): void;
+}
+```
+
+### Responsibilities
+
+- Program side:
+  - Calls `io.listen` to declare interests (topics and handlers).
+  - Calls `io.emit` to request side-effects.
+
+- Host side:
+  - Maps external sources (timers, websockets, HTTP, DB) to events and pushes them into the program via `dispatch`.
+  - Executes effects received from `onEffect` subscribers; potentially pushes result events back (e.g., `http.response`).
+  - Manages lifecycle (start/stop) and isolation (per session or per process).
+
+### Startup sequence and initial effects
+
+- The host should invoke `program.start([{ topic: 'app.init', data: {...} }])` to bootstrap.
+- User code can `io.listen "app.init"` to initialize state and immediately `io.emit` effects.
+- This supports emitting to external systems as the very first action (e.g., schedule work, send a greeting, request data).
+
+Example (Baba Yaga):
+
+```baba
+onInit : e ->
+  io.emit "cmd.fetch" { url: "https://api.example.com/data" };
+
+main : ->
+  io.listen "app.init" onInit;
+```
+
+### Reference Topics
+
+We recommend a small standard vocabulary:
+
+- `app.init` — sent once at startup
+- `app.tick` — periodic timer events
+- `http.request` / `http.response`
+- `ws.message` / `ws.send`
+- `db.query` / `db.result`
+
+These are guidelines; projects can add more namespaced topics.
+
+## Example Embedding Flow (Host Pseudocode)
+
+```ts
+const controller = program.start([{ topic: 'app.init', data: {} }]);
+
+controller.onEffect(async (eff) => {
+  if (eff.topic === 'http.request') {
+    const res = await fetch(eff.data.url, { method: eff.data.method });
+    controller.dispatch({ topic: 'http.response', data: { status: res.status } });
+  }
+  if (eff.topic === 'cmd.render') {
+    render(eff.data); // user-defined
+  }
+});
+
+// External source -> event
+ws.onmessage = (msg) => controller.dispatch({ topic: 'ws.message', data: msg });
+```
+
+## Testing Strategy
+
+- Treat user logic as pure functions of `(state, event) -> { state, effects }`.
+- Unit-test handlers and updaters by asserting emitted effects and next state.
+- Integration-test host harness by simulating effect execution and event feedback.
+
+## Summary
+
+- `io.listen` and `io.emit` define a minimal, opinionated bridge between Baba Yaga and the outside world.
+- A TEA/FRP-inspired loop ensures purity and testability.
+- A small host SDK surface (dispatch/onEffect) provides a unified way to embed programs across environments.
+
+## Application profiles (guidance)
+
+- Near real-time data processing
+  - Sources: streams, queues, file watchers -> `evt.ingest.*`
+  - Effects: enrichment, writes, notifications -> `cmd.write.*`, `cmd.notify.*`
+  - Backpressure: batch events or throttle at host; program remains pure
+
+- Games / simulations
+  - Drive time with `app.tick` at a fixed cadence
+  - Program updates state and emits `cmd.render` or `cmd.sound` effects; host renders
+
+- WebSocket comms
+  - Events: `ws.message` with parsed payload
+  - Effects: `ws.send` with outbound frames; host maps to actual socket
+
+- Data transformation/search
+  - Input events: `evt.query` or `evt.batch`
+  - Effects: `cmd.response` with transformed payloads
+
+This single event/effect interface scales across these use cases without leaking side-effects into program logic.
+
+