/** * ML store — placeholder shape for the ML engine state. * * Stream 7 wires WASM under this. For now the methods that mutate the engine * throw `not implemented`. The shape of the store and the signal types are * final — modes and primitives can read them. * * Why a Solid store + a separate Float32Array signal: * - `createStore` is great for object-like state with fine reactivity. * - Float32Array outputs are large and frequently updated; `createSignal` * with explicit reference replacement is cheaper. */ import { createSignal, type Accessor } from 'solid-js'; import { createStore, produce } from 'solid-js/store'; import { coreBus } from './bus'; export interface MLStoreState { exampleCount: number; /** Last training loss (final loss of last train() call). null = none yet. */ lastLoss: number | null; /** Last training run loss curve (per iteration). */ lossHistory: number[]; /** Current input vector size (matches active mode). */ inputSize: number; /** Current output vector size (matches active mode). */ outputSize: number; /** True while a synchronous or async training call is running. */ training: boolean; /** True when WASM is fully initialised. */ ready: boolean; } const EMPTY_OUTPUTS = new Float32Array(0); const NOT_IMPLEMENTED = (op: string): never => { throw new Error( `[ml-store] ${op} not implemented in stream-8 scaffold; awaits stream 7 (WASM bindings)` ); }; const [state, setState] = createStore({ exampleCount: 0, lastLoss: null, lossHistory: [], inputSize: 2, outputSize: 126, training: false, ready: false, }); const [outputs, setOutputs] = createSignal(EMPTY_OUTPUTS, { equals: false, // always notify even if reference reused }); const [weights, setWeights] = createSignal(EMPTY_OUTPUTS, { equals: false, }); export const mlStore = { // ---- read ---- state, outputs: outputs as Accessor, weights: weights as Accessor, // ---- internal setters (used by future WASM wiring; exposed for stub // wiring during this stream so primitive demos can drive values) ---- __setOutputs: setOutputs, __setState: setState, __setWeights: setWeights, // ---- ML lifecycle (stubbed) ---- initialize(_inputSize: number, _outputSize: number): Promise { return NOT_IMPLEMENTED('initialize'); }, setInput(_idx: number, _value: number): void { NOT_IMPLEMENTED('setInput'); }, process(): void { NOT_IMPLEMENTED('process'); }, addExample(_features: ReadonlyArray, _labels: ReadonlyArray): void { NOT_IMPLEMENTED('addExample'); }, train(_lr?: number, _maxIter?: number): number { return NOT_IMPLEMENTED('train'); }, trainAsync(_lr?: number, _maxIter?: number): Promise { return NOT_IMPLEMENTED('trainAsync'); }, drawWeights(_spread: number): void { NOT_IMPLEMENTED('drawWeights'); }, moveWeights(_speed: number, _spread: number, _pinMask?: Uint8Array): void { NOT_IMPLEMENTED('moveWeights'); }, evalLoss(): number | null { return null; }, inferBatch(_points: ReadonlyArray): Float32Array { return NOT_IMPLEMENTED('inferBatch'); }, getLayerStats(): Float32Array { return EMPTY_OUTPUTS; }, reset(): void { NOT_IMPLEMENTED('reset'); }, clearExamples(): void { setState(produce((s) => { s.exampleCount = 0; })); coreBus.emit('ml.examples_cleared', undefined); }, }; export type MLStore = typeof mlStore;