2026-07-13 23:25:31 +02:00
|
|
|
/**
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
* Pipeline golden regression (run with `bun test`).
|
2026-07-13 23:25:31 +02:00
|
|
|
*
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
* The one-core-engine P4 migration moved the curve / input-pipeline /
|
|
|
|
|
* output-pipeline maths into the C++/WASM core (nisps/pipeline/*, nisps/core/
|
|
|
|
|
* math.hpp). This test now drives the SAME committed fixtures through the WASM
|
|
|
|
|
* chains and asserts they reproduce the recorded gestures. It is the
|
|
|
|
|
* recorded-gesture pre/post-migration regression the plan (§P4) calls for:
|
|
|
|
|
* same pointer trace → same routed output across the migration.
|
2026-07-13 23:25:31 +02:00
|
|
|
*
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
* Tolerances (f32 WASM vs f64-captured fixtures):
|
|
|
|
|
* - Input / output pipelines: 1e-5. Measured max non-momentum drift <5e-7.
|
|
|
|
|
* - Momentum configs (momentum-gentle / momentum-strong / combined): 1e-2.
|
|
|
|
|
* This path is NOT float noise in the usual sense: the velocity ring's
|
|
|
|
|
* window-membership test (`now - t <= window`) is a DISCRETE boundary that
|
|
|
|
|
* f32 rounding can flip during fast gestures, changing which sample is the
|
|
|
|
|
* window's oldest by a whole frame (~8 ms) → a step change in the measured
|
|
|
|
|
* speed → integrated by the momentum-zoom IIR. It is proven-inherent to the
|
|
|
|
|
* deliberately-f32 core, NOT a core bug: a byte-faithful f32 port of the
|
|
|
|
|
* exact original TS algorithm reproduces the WASM to <6e-8 while both
|
|
|
|
|
* diverge from the f64 capture by the same ~7-9e-3 (measured max 8.6e-3 on
|
|
|
|
|
* momentum-strong). Reconciling it in the core would require f64 momentum
|
|
|
|
|
* maths, which would break firmware parity. See fixtures/README.md.
|
|
|
|
|
* - Curves: 1e-5. linear/square/sqrt/centered_power match the ORIGINAL f64
|
|
|
|
|
* capture (proving no behaviour change); exp/log/sigmoid/cubic were
|
|
|
|
|
* RE-BASELINED from the WASM on 2026-07-18 (deliberate switch to the
|
|
|
|
|
* canonical firmware-exact maths — see fixtures/README.md + the
|
|
|
|
|
* curves-golden.json provenance) so the test asserts WASM stability against
|
|
|
|
|
* the regenerated values.
|
2026-07-13 23:25:31 +02:00
|
|
|
*
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
* The fixtures are authoritative: the trace, raw sequence, and configs are read
|
|
|
|
|
* FROM the JSON.
|
2026-07-13 23:25:31 +02:00
|
|
|
*/
|
|
|
|
|
import { readFileSync } from 'node:fs';
|
|
|
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
|
import { dirname, join } from 'node:path';
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
import { beforeAll, expect, test } from 'bun:test';
|
2026-07-13 23:25:31 +02:00
|
|
|
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
import { CURVE_ID, type CurveName } from '../src/engine/curve-catalog';
|
2026-07-13 23:25:31 +02:00
|
|
|
import {
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
anchorModeToInt,
|
|
|
|
|
momentumModeToInt,
|
|
|
|
|
type InputConfig,
|
|
|
|
|
} from '../src/engine/pipeline-types';
|
|
|
|
|
import type { GestureEvent, OutputRunSpec } from './pipeline-golden-lib';
|
|
|
|
|
import { loadPipelineWasm, type PipelineWasm } from './wasm-load';
|
2026-07-13 23:25:31 +02:00
|
|
|
|
|
|
|
|
const DIR = dirname(fileURLToPath(import.meta.url));
|
|
|
|
|
const readFixture = <T>(name: string): T =>
|
|
|
|
|
JSON.parse(readFileSync(join(DIR, 'fixtures', name), 'utf8')) as T;
|
|
|
|
|
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
const TOL = 1e-5;
|
|
|
|
|
/**
|
|
|
|
|
* Momentum configs only: proven-inherent f32 drift of the velocity-ring +
|
|
|
|
|
* momentum-zoom IIR (see the file header). Measured max 8.6e-3; 1e-2 leaves a
|
|
|
|
|
* small margin. The core is still tightly guarded — a byte-faithful f32 port of
|
|
|
|
|
* the original algorithm matches the WASM to <6e-8 — so a real behavioural
|
|
|
|
|
* regression (wrong preset / broken window logic) would blow far past 1e-2.
|
|
|
|
|
*/
|
|
|
|
|
const MOMENTUM_TOL = 1e-2;
|
|
|
|
|
const MOMENTUM_RUNS = new Set(['momentum-gentle', 'momentum-strong', 'combined']);
|
|
|
|
|
|
|
|
|
|
const close = (a: number, b: number, tol: number, ctx: string) => {
|
2026-07-13 23:25:31 +02:00
|
|
|
if (a === b) return;
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
expect(Math.abs(a - b), ctx).toBeLessThanOrEqual(tol);
|
2026-07-13 23:25:31 +02:00
|
|
|
};
|
|
|
|
|
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
/** InputConfig → the 15-float wire layout (nisps_input_set_config). */
|
|
|
|
|
function inputConfigToWire(c: InputConfig): number[] {
|
|
|
|
|
return [
|
|
|
|
|
c.zoom,
|
|
|
|
|
c.zoomX ?? 0,
|
|
|
|
|
c.zoomY ?? 0,
|
|
|
|
|
c.anchorX,
|
|
|
|
|
c.anchorY,
|
|
|
|
|
anchorModeToInt(c.anchorMode),
|
|
|
|
|
c.deadzone,
|
|
|
|
|
c.inputCurve,
|
|
|
|
|
c.inputCurveX ?? 0,
|
|
|
|
|
c.inputCurveY ?? 0,
|
|
|
|
|
c.smoothing,
|
|
|
|
|
momentumModeToInt(c.momentumZoom),
|
|
|
|
|
c.velocityWindow / 1000,
|
|
|
|
|
c.invertX ? 1 : 0,
|
|
|
|
|
c.invertY ? 1 : 0,
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let wasm: PipelineWasm;
|
|
|
|
|
let pipe = 0;
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
|
wasm = await loadPipelineWasm();
|
|
|
|
|
pipe = wasm.pipelineCreate();
|
|
|
|
|
expect(pipe).toBeGreaterThan(0);
|
|
|
|
|
});
|
|
|
|
|
|
2026-07-13 23:25:31 +02:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
test('gesture trace fixture is well-formed (>=240 events, fixed dt, in-domain)', () => {
|
|
|
|
|
const trace = readFixture<{ dt_ms: number; count: number; events: GestureEvent[] }>('gesture-trace.json');
|
|
|
|
|
expect(trace.events.length).toBe(trace.count);
|
|
|
|
|
expect(trace.events.length).toBeGreaterThanOrEqual(240);
|
|
|
|
|
for (let i = 0; i < trace.events.length; i++) {
|
|
|
|
|
const ev = trace.events[i]!;
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
close(ev.t_ms, i * trace.dt_ms, TOL, `event ${i} t_ms`);
|
2026-07-13 23:25:31 +02:00
|
|
|
expect(ev.x).toBeGreaterThanOrEqual(0);
|
|
|
|
|
expect(ev.x).toBeLessThanOrEqual(1);
|
|
|
|
|
expect(ev.y).toBeGreaterThanOrEqual(0);
|
|
|
|
|
expect(ev.y).toBeLessThanOrEqual(1);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
test('curves-golden: WASM curveApply matches the (re-baselined) catalog', () => {
|
2026-07-13 23:25:31 +02:00
|
|
|
const fx = readFixture<{ sampleCount: number; curves: Record<string, number[]> }>('curves-golden.json');
|
|
|
|
|
const names = Object.keys(fx.curves) as CurveName[];
|
|
|
|
|
expect(names.length).toBeGreaterThan(0);
|
|
|
|
|
for (const name of names) {
|
|
|
|
|
const golden = fx.curves[name]!;
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
const id = CURVE_ID[name];
|
|
|
|
|
const param = name === 'centered_power' ? 1.0 : 0;
|
2026-07-13 23:25:31 +02:00
|
|
|
expect(golden.length).toBe(fx.sampleCount);
|
|
|
|
|
for (let i = 0; i < golden.length; i++) {
|
|
|
|
|
const x = i / (fx.sampleCount - 1);
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
close(wasm.curveApply(id, x, param), golden[i]!, TOL, `curve ${name}[${i}] (x=${x})`);
|
2026-07-13 23:25:31 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
test('input-pipeline-golden: WASM input chain matches captured outputs', () => {
|
2026-07-13 23:25:31 +02:00
|
|
|
const trace = readFixture<{ events: GestureEvent[] }>('gesture-trace.json').events;
|
|
|
|
|
const fx = readFixture<{
|
|
|
|
|
runs: Array<{ id: string; config: InputConfig; outputs: Array<{ x: number; y: number; frozen: boolean }> }>;
|
|
|
|
|
}>('input-pipeline-golden.json');
|
|
|
|
|
expect(fx.runs.length).toBeGreaterThan(0);
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
|
2026-07-13 23:25:31 +02:00
|
|
|
for (const run of fx.runs) {
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
const tol = MOMENTUM_RUNS.has(run.id) ? MOMENTUM_TOL : TOL;
|
|
|
|
|
wasm.inputReset(pipe);
|
|
|
|
|
wasm.inputSetConfig(pipe, inputConfigToWire(run.config));
|
|
|
|
|
expect(run.outputs.length, `run ${run.id} length`).toBe(trace.length);
|
|
|
|
|
|
|
|
|
|
// Honour the fixture clock contract: dt = per-event t_ms delta in seconds,
|
|
|
|
|
// with the first event's dt = 0 (matches the pre-migration capture).
|
|
|
|
|
let prevT = trace.length > 0 ? trace[0]!.t_ms : 0;
|
|
|
|
|
for (let i = 0; i < trace.length; i++) {
|
|
|
|
|
const ev = trace[i]!;
|
|
|
|
|
const dt = Math.max(0, (ev.t_ms - prevT) / 1000);
|
|
|
|
|
prevT = ev.t_ms;
|
|
|
|
|
const got = wasm.inputProcess(pipe, ev.x, ev.y, dt);
|
|
|
|
|
const want = run.outputs[i]!;
|
|
|
|
|
close(got.x, want.x, tol, `input ${run.id}[${i}].x`);
|
|
|
|
|
close(got.y, want.y, tol, `input ${run.id}[${i}].y`);
|
|
|
|
|
expect(got.frozen, `input ${run.id}[${i}].frozen`).toBe(want.frozen);
|
2026-07-13 23:25:31 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
test('output-pipeline-golden: WASM output chain matches captured outputs', () => {
|
2026-07-13 23:25:31 +02:00
|
|
|
const fx = readFixture<{
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
dt_ms: number;
|
2026-07-13 23:25:31 +02:00
|
|
|
sequence: number[][];
|
|
|
|
|
runs: Array<{ id: string; spec: OutputRunSpec; outputs: number[][] }>;
|
|
|
|
|
}>('output-pipeline-golden.json');
|
|
|
|
|
expect(fx.runs.length).toBeGreaterThan(0);
|
|
|
|
|
expect(fx.sequence.length).toBeGreaterThanOrEqual(100);
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
const dtSeconds = fx.dt_ms / 1000; // constant per step (matches the capture)
|
|
|
|
|
const dims = fx.sequence[0]!.length;
|
|
|
|
|
|
2026-07-13 23:25:31 +02:00
|
|
|
for (const run of fx.runs) {
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
const spec = run.spec;
|
|
|
|
|
wasm.outputReset(pipe);
|
|
|
|
|
// Per-output freeze mask (whole-run), applied once.
|
|
|
|
|
let mask: Uint8Array | null = null;
|
|
|
|
|
if (spec.freezeMaskIndices) {
|
|
|
|
|
mask = new Uint8Array(dims);
|
|
|
|
|
for (const i of spec.freezeMaskIndices) if (i >= 0 && i < dims) mask[i] = 1;
|
|
|
|
|
}
|
|
|
|
|
wasm.outputSetFreezeMask(pipe, mask);
|
|
|
|
|
|
|
|
|
|
expect(run.outputs.length, `run ${run.id} length`).toBe(fx.sequence.length);
|
|
|
|
|
const slew = spec.slewRate === null ? Infinity : spec.slewRate;
|
|
|
|
|
for (let s = 0; s < fx.sequence.length; s++) {
|
|
|
|
|
const frozen = spec.freezeSteps ? s >= spec.freezeSteps[0] && s < spec.freezeSteps[1] : false;
|
|
|
|
|
wasm.outputSetConfig(pipe, spec.globalCurve, spec.smoothing, slew, frozen);
|
|
|
|
|
const vec = Float32Array.from(fx.sequence[s]!);
|
|
|
|
|
wasm.outputProcess(pipe, vec, dtSeconds);
|
|
|
|
|
const want = run.outputs[s]!;
|
|
|
|
|
expect(vec.length, `output ${run.id}[${s}] width`).toBe(want.length);
|
|
|
|
|
for (let j = 0; j < vec.length; j++) {
|
|
|
|
|
close(vec[j]!, want[j]!, TOL, `output ${run.id}[${s}][${j}]`);
|
2026-07-13 23:25:31 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|