JS Sensitivity Profiler: Standalone Package
Summary
Port the interactive sensitivity-profiling capability of ipysensitivityprofiler (Python/ipywidgets) to a standalone JS/TS package with no Jupyter, no Python runtime, and no dependency on JENN. Takes any JS-computable model x → y and renders a grid of local one-at-a-time sensitivity charts, matching the existing library's contract (models, xmin, xmax, ymin, ymax, x0, resolution, xlabels, ylabels).
Repo Decision: Separate Package
This lives in its own repo, not inside JENN or JENN-MCP. ipysensitivityprofiler already establishes the right precedent in Python — it takes any callable with signature y = f(x) and has no knowledge of JENN, gradients, or neural nets specifically. The JS port should preserve that same boundary.
Reasons:
- Reusability beyond JENN — anyone with a JS-computable model (a closed-form formula, a different surrogate technique, a lookup table) gets the profiler for free, not just JENN users.
- Independent lifecycle — a visualization component and a training/MCP tool server change for different reasons and on different cadences.
- Consistency with existing architecture — mirrors the separation already chosen for the Python version rather than introducing a new one.
JENN-MCP's generate_profiler_app tool becomes a consumer of this package (passes it a JS-exported inference function, gets back a rendered app) — the same relationship JENN has with ipysensitivityprofiler today.
Scope Cut: No Draggable Point
The Python version's draggable dot (bidirectionally linked to its slider, drag either and both move) is cut from v1. Sliders alone provide equivalent functionality — set x0 per input — without the sync complexity of live drag-to-chart-to-slider binding across a grid of independent charts. This was the single most fiddly interaction in the original; removing it is the main thing that makes this a small-to-medium lift rather than a larger one.
In Scope (v1)
- Grid of line charts, one per (input, output) pair — local one-at-a-time sensitivity sweep, not a full n-dimensional surface (matches existing behavior).
- Sliders to set
x0 per input; changing a slider triggers a single batched recompute (x → y over the sweep grid) and updates all affected charts.
- Independent range sliders per axis (x and y) to rescale chart limits.
- Multi-model overlay: multiple lines per chart (different dash styles), matching the comparison feature in the Python version.
- Static, shareable output — no backend process required as long as the model is a pure JS function.
Relationship to ipysensitivityprofiler (Python) and Value of Maintaining Both
These are not two implementations of "the same" thing that happen to run in different languages — they serve genuinely different classes of model input, and that's the reason to keep both rather than deprecate one in favor of the other.
Python/ipywidgets version: runs inside a live Jupyter kernel, so it can call any Python callable — arbitrary code, external solvers, wrapped Fortran/C++, proprietary licensed physics codes, database or file I/O, anything expressible in Python. The cost is that it requires a running kernel/environment; it's not shareable as a standalone artifact.
JS version: requires no backend, is trivially shareable (a single file or static bundle, opens in any browser), but only works for models that can be expressed as pure JS-computable functions. That's a strict subset of what's expressible in Python — a trained neural net's forward pass qualifies (matrix multiplies + activations), but a call out to an external FEA solver or a proprietary licensed code does not, and never will without a backend of some kind.
So the two aren't redundant or competing — they cover different points on the "what is the model" spectrum:
- If the model can be exported to a pure JS forward pass → JS version gives a zero-dependency, shareable, instant-load experience.
- If the model requires arbitrary Python execution → Python version is the only option; the JS version simply cannot express it.
Sync Challenges
Because the two are built on different runtimes and rendering stacks (bqplot/ipywidgets/traitlets vs. a JS charting library + framework state), there's no way to keep them "in sync" at the code level — they'll always be independent implementations. The real sync risk is at the behavior/contract level, not the code level:
- Feature or behavior added to one (e.g., a change to how axis range sliders interact with recompute, a new labeling convention) can silently drift from the other if there's no shared reference for expected behavior.
- Users who move between the two (e.g., prototyping in a notebook with the Python version, then exporting to a standalone JS app) will notice inconsistencies if the interaction model diverges, even if each version works correctly in isolation.
Mitigation direction: a shared behavior spec (not shared code) describing the interaction contract — what sliders/ranges do, how multi-model overlay renders, what "resolution" means — that both implementations are checked against. Longer-term, a small set of shared test fixtures (same model + same bounds should produce equivalent chart data in both) would catch drift automatically rather than relying on manual comparison.
This is a distinct problem from the JENN-specific numerical-drift concern (JS inference matching Python inference within tolerance) raised in the JS export ticket — that one is about model fidelity; this one is about interaction/behavior fidelity between two UI implementations.
Open Questions
- Charting library choice for JS (Plotly vs. a lighter d3-based approach) — affects how much of the grid/multi-trace/range-rescale behavior comes for free vs. needs custom implementation.
- Whether the shared behavior spec is written before or after the first JS implementation pass (spec-first risks over-designing before real constraints surface; implementation-first risks the spec just describing whatever got built).
- Packaging: single-file HTML output vs. installable JS package vs. both.
JS Sensitivity Profiler: Standalone Package
Summary
Port the interactive sensitivity-profiling capability of
ipysensitivityprofiler(Python/ipywidgets) to a standalone JS/TS package with no Jupyter, no Python runtime, and no dependency on JENN. Takes any JS-computable modelx → yand renders a grid of local one-at-a-time sensitivity charts, matching the existing library's contract (models,xmin,xmax,ymin,ymax,x0,resolution,xlabels,ylabels).Repo Decision: Separate Package
This lives in its own repo, not inside JENN or JENN-MCP.
ipysensitivityprofileralready establishes the right precedent in Python — it takes any callable with signaturey = f(x)and has no knowledge of JENN, gradients, or neural nets specifically. The JS port should preserve that same boundary.Reasons:
JENN-MCP's
generate_profiler_apptool becomes a consumer of this package (passes it a JS-exported inference function, gets back a rendered app) — the same relationship JENN has withipysensitivityprofilertoday.Scope Cut: No Draggable Point
The Python version's draggable dot (bidirectionally linked to its slider, drag either and both move) is cut from v1. Sliders alone provide equivalent functionality — set
x0per input — without the sync complexity of live drag-to-chart-to-slider binding across a grid of independent charts. This was the single most fiddly interaction in the original; removing it is the main thing that makes this a small-to-medium lift rather than a larger one.In Scope (v1)
x0per input; changing a slider triggers a single batched recompute (x → yover the sweep grid) and updates all affected charts.Relationship to
ipysensitivityprofiler(Python) and Value of Maintaining BothThese are not two implementations of "the same" thing that happen to run in different languages — they serve genuinely different classes of model input, and that's the reason to keep both rather than deprecate one in favor of the other.
Python/ipywidgets version: runs inside a live Jupyter kernel, so it can call any Python callable — arbitrary code, external solvers, wrapped Fortran/C++, proprietary licensed physics codes, database or file I/O, anything expressible in Python. The cost is that it requires a running kernel/environment; it's not shareable as a standalone artifact.
JS version: requires no backend, is trivially shareable (a single file or static bundle, opens in any browser), but only works for models that can be expressed as pure JS-computable functions. That's a strict subset of what's expressible in Python — a trained neural net's forward pass qualifies (matrix multiplies + activations), but a call out to an external FEA solver or a proprietary licensed code does not, and never will without a backend of some kind.
So the two aren't redundant or competing — they cover different points on the "what is the model" spectrum:
Sync Challenges
Because the two are built on different runtimes and rendering stacks (
bqplot/ipywidgets/traitletsvs. a JS charting library + framework state), there's no way to keep them "in sync" at the code level — they'll always be independent implementations. The real sync risk is at the behavior/contract level, not the code level:Mitigation direction: a shared behavior spec (not shared code) describing the interaction contract — what sliders/ranges do, how multi-model overlay renders, what "resolution" means — that both implementations are checked against. Longer-term, a small set of shared test fixtures (same model + same bounds should produce equivalent chart data in both) would catch drift automatically rather than relying on manual comparison.
This is a distinct problem from the JENN-specific numerical-drift concern (JS inference matching Python inference within tolerance) raised in the JS export ticket — that one is about model fidelity; this one is about interaction/behavior fidelity between two UI implementations.
Open Questions