Documentation
¶
Overview ¶
Command core-runtime is the Gothic Framework full-Go STATIC CORE: a prebuilt, type-agnostic RPC / registration hub.
Why full-Go (standard Go GOOS=js GOARCH=wasm), not TinyGo ¶
The core is compiled with the standard Go toolchain so it has the full standard library (encoding/json, regexp, crypto, time, locale-aware formatting) that TinyGo lacks. Later phases grow the core into a thick services hub (durable state cache, generic wire interpreter); those need the full stdlib. TinyGo stays the compiler for per-page/per-component modules because they must be small and are rebuilt on every hot reload.
Why static (prebuilt once, committed as an artifact, never rebuilt on save) ¶
A full-Go js/wasm build is slow and large — rebuilding it on every hot-reload keystroke would wreck DX. The core is app-INDEPENDENT (framework code, never user types), so it is compiled ONCE at framework-release time, content-hashed, embedded in the CLI, and merely COPIED into public/ on init and on build. It is deliberately NOT part of the GenerateAll per-page rebuild set.
Coexistence with TinyGo components ¶
The core loads through its own wasm_exec shim slot (window.__gothicGoClasses["gothic-core-exec.js"]) so its standard-Go `Go` constructor never collides with the TinyGo `Go` used by per-instance components on the same page.
Asyncify safety on the RETURN path ¶
The core must NEVER dispatchEvent synchronously. Its ack and online-announce fire BACK into a registering TinyGo component; a synchronous dispatchEvent would run that component's listener nested inside the component's own, still-unwinding asyncify turn → the documented `RuntimeError: unreachable` re-entrancy crash (the same reason topic.go routes broadcasts through __gothicDispatchAsync/queueMicrotask, and why the component's own register send in events.go is queueMicrotask'd). Every core→component dispatch here is therefore scheduled on a fresh microtask (see scheduleDispatch). Only the SCHEDULING is deferred — the listeners are still installed synchronously before the online announce, so the "listeners installed before online" ordering holds.
What it does (foundation only) ¶
The core boots, installs a control-plane registration listener on the `document` bus, records each registration OPAQUELY (it stores the schema descriptor verbatim WITHOUT interpreting it — the generic interpreter is DEFERRED to a later phase), and acks. NO topic logic lives here yet (that comes with the topic hub). This is the type-agnostic hub and its handshake, nothing more.
The record→ack DECISION (whether to record, under which key, which scope to ack) is factored into the pure, host-tested pkg/wasm/core-runtime/protocol package; this file is the thin js.Value adapter around it. The full register→ack round-trip over a LIVE WASM instance cannot be driven from a host Go test — it is exercised by the `wasm-core.spec.ts` Playwright e2e on TestGothic.