Changelog — ionworks-schema

All notable changes to this package are documented here. The format is based on Keep a Changelog, and this package follows Semantic Versioning.

For platform-wide release notes (Studio, pipeline, SDK, and more), see docs.ionworks.com/changelog.

[0.34.0] - 2026-11-02

Breaking changes

  • calculations.ElectrodeBalanceFromFirstCycleEfficiency no longer reads "Nominal cell capacity [A.h]"; cyclable lithium is first cycle efficiency times positive electrode capacity, so existing configs give different stoichiometry limits (#2613)

Added

  • models.SimulationSettings(discretisation_kwargs=...) carries pybamm.Discretisation options for a model, parameterized model or simulation run (#2598)

  • calculations.ElectrodeBalanceFromFirstCycleEfficiency(options=...): composite electrodes via particle phases; the formation loss is now taken against positive electrode capacity, not nominal capacity (#2613)

[0.33.0] - 2026-10-23

Added

  • calculations.ElectrodeBalanceFromFirstCycleEfficiency: stoichiometry limits and initial concentrations at 100% SOC in one step, from both electrodes’ geometry, the nominal capacity and the first cycle efficiency (#2111)

  • calculations.ElectrodeGeometryFromLoading(electrode): an electrode’s thickness, active material volume fraction and porosity from its coating mass loading and press density (#2111)

Changed

  • CyclableLithium.method and ElectrodeVolumeFractionFromLoading.method are typed as their allowed values rather than free strings, so an unknown method is rejected when the config is built (#2111)

[0.32.1] - 2026-10-20

Changed

  • Requires pandas>=2.2.2. Earlier pandas releases do not import alongside numpy 2.

[0.32.0] - 2026-10-09

Added

  • iws.direct_entries.DirectEntry(pipeline_id=..., keep=[...]) takes only the named parameters from a completed pipeline. A name the pipeline did not produce, or an empty keep, is an error. Without keep, every parameter is taken, as before.

  • iws.direct_entries.DirectEntry(cell_spec_id=..., mapping={...}) reads parameter values from a cell specification. mapping gives each parameter’s JSON path in the specification (e.g. "anode.properties.thickness"), and each value is converted to the unit in the parameter’s name. Values are read once, when the pipeline is submitted.

  • DirectEntry.provenance records where each parameter came from: the path it was read from, and the value and unit written there.

Deprecated

  • Constructing iws.SimplePipeline emits a DeprecationWarning. Use iws.Pipeline, which takes the same elements. SimplePipeline will be removed no earlier than November 2026.

[0.31.0] - 2026-09-30

Added

  • CycleAgeingOptions.split_cc_cv: emit a step the cycler logged as one CC-CV charge as a constant-current step followed by a constant-voltage step. Default True. Applies only to an experiment generated from data, like termination.

Changed

  • Docstrings for Penalty and Constraint now say that each term contributes regularizer_weight * fun**2 to the cost. Pass the unsquared quantity as fun.

  • Optimizer docstrings now say that Constraint objects are applied as a penalty on the cost by every scipy optimizer and method.

[0.30.0] - 2026-09-29

Breaking changes

  • DataLoaderOptions and DataLoaderTransforms drop the gitt_to_ocp field, so passing it now fails validation. Use rest_to_ocp instead.

Changed

  • Raised the pybamm lower bound to >=26.9.0.0, and the matplotlib lower bound in the plot extra to >=3.11.2.

[0.29.0] - 2026-09-25

Added

  • TimeRangeSpec accepts duration as an alternative to end, measured from start: TimeRangeSpec(start=0.0, duration=86_400.0) is the first day of a test. It resolves to end at construction, so the emitted config still carries only start and end. Passing both end and duration, or a negative duration, is rejected.

  • TimeRangeSpec is exported from the top-level ionworks_schema package.

[0.28.0] - 2026-09-24

Added

  • AnalysisSpec, a selector (analysis_id, analysis_type, name) for one of a measurement’s stored analyses. A data input of {"data": "db:<measurement_id>", "analysis": {...}}, or an ionworksdata.AnalysisLoader, reads that analysis as an objective’s data instead of the measurement’s time series, so a CycleAgeing fit can take its targets from the measurement it is fitted against. analysis cannot be combined with options or time_range.

  • CycleAgeing data may be sparse: a NaN in a target column means the variable was not measured at that cycle, and that row is left out for that variable only, rather than every variable having to be measured at every cycle.

Changed

  • analysis and time_range are now reserved keys of a dict data input, so a column literally named either is read as a payload key.

Fixed

  • A time_range combined with first_step / last_step narrows within the chosen steps, rather than shifting which steps are chosen.

[0.27.0] - 2026-09-22

Added

  • CycleAgeingOptions takes termination and use_cv, matching the new DataLoader.generate_experiment arguments. Both apply only to a generated experiment; passing either alongside an explicit one raises.

Fixed

  • A pybamm.Symbol fun on a Constraint or Penalty now survives submission through the API. to_config emits the symbol as a pybamm JSON tree, and the schema rebuilds it on validation, where previously the serialized dict was rejected against is-instance[Symbol] — so a symbolic constraint or penalty was local-only.

  • A DataLoader passed as a CycleAgeingOptions experiment is wrapped in the "from data" form its consumers dispatch on. An unwrapped reference was resolved by nobody and then rejected by the parser. This also lets the protocol come from a different measurement than the fitted data.

  • An entry or DirectEntry config that names more than one source of parameters — path, values, pipeline_id — is rejected with an error naming the keys that clash, instead of silently picking one.

[0.26.0] - 2026-09-15

Breaking changes

  • A field value with no wire form now raises when the schema is built, naming the field, instead of reaching the server as a repr string such as "<pybamm...SPM object at 0x...>". Nested failures report the full path (options: model:). Convert such values to a number, string, list, dict, or pybamm object before putting them in a schema.

  • callbacks and cost_logger hold live objects and now raise on to_config(). They were never wire-capable — previously they were embedded raw and failed later, more confusingly, in the API client’s JSON encoding.

  • custom_parameters is rejected by name; use parameters instead. The positional slot is retained so a positional caller gets an error rather than silently shifting constraints into the vacated position.

Changed

  • Parameter serialisation moved onto the type: ParameterValuesLike carries the serialiser, so it applies on both construction and assignment for every field that uses it, rather than being re-declared per owner. This also fixes custom_parameters mappings never having their citations dropped or scalars flattened.

  • Re-serialising an already-serialised parameter mapping now short-circuits instead of deep-walking the expanded symbol tree, so a read-modify-write on .parameters no longer pays the full cost.

Removed

  • The internal pybamm-model serialiser, superseded by pybamm’s own BaseModel.to_config(). The old helper reported any non-lithium-ion model as "custom"; pybamm’s emits the real module.

[0.25.0] - 2026-09-09

Added

  • penalize Xj complement bounds on iws.objectives.MSMRHalfCellOptions (default False) penalizes a reformulated Xj complement that falls outside the final Xj bounds. Only used with the reformulate method.

Changed

  • MSMRHalfCell documents that the capacity origin is carried by the electrode’s lower excess capacity, and how to seed it.

  • Constraint and Penalty document that a pybamm.Symbol fun is local only — it does not survive submission through the API, where the serialized symbol is rejected in validation.

[0.24.1] - 2026-09-08

Added

  • iws.example_data(name) returns the path to a small dataset bundled with the package, and iws.list_example_data() names the ones available. They back the worked examples in the documentation, so an example can be copied out and run as-is with no download and no network. The datasets are synthetic sample data for illustration — substitute your own export, or read a measurement from the platform.

  • Worked examples in the documentation for current-driven fitting, cycle ageing, EIS, and MSMR OCP, each rendered with its figure and runnable from a copy.

[0.24.0] - 2026-09-07

Added

  • Post-fit analysis is expressible as a pipeline element: iws.LinearConfidenceInterval for linear confidence intervals and iws.SobolSensitivity for Sobol sensitivity. Both take the same objectives and parameters as a DataFit, and accept only a PointEstimate optimizer, since they analyse a fit rather than performing one.

  • iws.ConfidenceIntervalResult and iws.SensitivityResult type their results, so intervals and sensitivity indices are reachable off the result object rather than by reading raw job metadata.

  • An analysis element placed after a DataFit with the same objectives and parameters picks up the fitted point automatically, so the parameters do not have to be restated.

[0.23.0] - 2026-09-04

Added

  • 33 schema classes that their packages defined but never re-exported are now reachable as attributes: 15 in calculations, 11 in objectives, 5 in models, plus direct_entries.BaseInterpolation and objective_functions.Regularizer. Every *Options companion was affected — iws.objectives.CurrentDrivenOptions, iws.models.ECMOptions, iws.calculations.ElectrodeSOHOptions and their siblings did not exist as attributes at all, so building a fit against a typed options object was not possible without reaching into a submodule. LumpedSPMR is also newly exported alongside its options.

[0.22.0] - 2026-08-31

Added

  • A typed result hierarchy in the new ionworks_schema.results module, exported at the top level: BaseResults plus ParameterEstimatorResult, OptimizationResult, EnsembleResult, PosteriorResult, RegressionResult, ValidationResult, and PassthroughResult, with from_config to rebuild one from a config. Results round-trip through to_config()/from_config() and expose plot_fit_results() and plot_trace(). Plotting needs matplotlib, available as an optional extra: pip install 'ionworks-schema[plot]'.

  • Lazy overlay, trace, posterior, and series fields on BaseResults, fetched on first read and cached. overlay gives decimated data suited to figures; series gives the full-resolution per-objective model-vs-data channels as {objective: {channel: [values]}} for saving or further analysis.

  • A new ionworks_schema.plots module describing what a panel contains — its traces and axis labels — independently of how it is drawn, so the same description backs both the schema’s own plotting and the pipeline’s.

Changed

  • StoichiometryLimitsFromCapacity now rejects a missing usable capacity at validation time when particle phases contains "2", instead of accepting the config and failing once the calculation runs. usable capacity is per direction: a joint-hysteresis fit uses a different value for charge than for discharge, so run one calculation per direction with that direction’s value.

  • Requires pybamm 26.8.0.0 or newer.

[0.21.0] - 2026-08-25

Added

  • TimeRangeSpec, and a time_range field on DataPayloadSpec, describing an elapsed-seconds window that pins a db: source to the samples it held when the run was first pinned. start and end are Time [s] values from the first sample rather than wall-clock datetimes, and a window whose end precedes its start is rejected at validation.

Changed

  • Declares support for Python 3.13.

[0.20.0] - 2026-08-18

Breaking changes

  • The options field on every model, objective, and calculation class is now a typed options model instead of a free-form dict[str, Any]. Unknown or misspelt keys are rejected when the class is constructed, instead of being silently accepted (and previously ignored) at runtime. Pass a plain dict as before — it’s still validated against the typed schema — or import the new *Options class (e.g. ECMOptions, CalendarAgeingOptions, StoichiometryLimitsFromCapacityOptions) directly for autocomplete and static checking.

Added

  • StoichiometryLimitsFromCapacityOptions gains negative voltage limits, positive voltage limits, and usable capacity options, used to solve the shared stoichiometry window for a composite electrode from its lower-excess capacity.

[0.19.0] - 2026-08-11

Breaking changes

  • Simulation objectives (CalendarAgeing, CurrentDriven, CycleAgeing, EIS, Pulse, and any other SimulationObjective subclass) now require a model, and construction fails without one. Pass it as options={"model": <pybamm model>}, or name a stored model with options={"parameterized_model_id": <id>}. Previously an objective with no model was accepted and only failed later, once the fit ran.

    # before
    obj = iws.objectives.Pulse(data_input="file:gitt.csv")
    
    # after
    obj = iws.objectives.Pulse(data_input="file:gitt.csv", options={"model": "SPM"})
    
  • A parameter whose value is None is now rejected instead of being serialised as a null the rest of the stack cannot use. The error names every offending key. Give the parameter a value, or omit the key entirely.

  • A measurement given as a string must now start with a locator prefix saying where to read it from — file:, folder:, or db:. The loader already required this and rejected anything else; the rejection now happens when the config is built. Rewrite a bare path as file:path/to/data.csv.

  • A measurement given as a dict is now routed by its keys to a named, strictly-validated shape, so a misspelt key or option is rejected at construction rather than silently ignored. time_series, steps, data, options, and metadata are consequently reserved: a dict using one of them is read as a payload key, not as a column of that name. A dict matching none of the named shapes is still accepted as a plain column mapping.

Added

  • DataLoaderOptions and DataLoaderTransforms schemas, giving the measurement-loading option surface a validated, documented type. Both are accepted anywhere loader options are taken, alongside a plain mapping.

Changed

  • The design-optimization optimizer field is now typed rather than free-form, so an unsupported optimizer is caught at construction.

[0.18.1] - 2026-08-10

Changed

  • Documented that MultiCost.calculation_structure accepts only None for every value. A MultiCost weights and sums what its component costs return, so per-variable scoping belongs on those components. Construction does not reject a variable list: converting such a config directly to a runtime cost raises, while sending it as a stored configuration drops the list and logs a warning. Behaviour is unchanged — the constraint was already real but undocumented.

[0.18.0] - 2026-08-06

Breaking changes

  • MultiCost.costs now takes a list of costs instead of a {cost: weight} mapping. A bare cost gets weight 1.0; wrap one in the new WeightedCost to give it another. At least one component is required.

    # before
    cost = iws.costs.MultiCost(costs={rmse: 1.0, max_err: 0.25})
    # after
    cost = iws.costs.MultiCost(
        costs=[iws.costs.RMSE(), iws.costs.WeightedCost(iws.costs.Max(), 0.25)]
    )
    

    Passing a mapping now raises a ValueError naming the accepted form. The same change landed in ionworkspipeline, so the two packages now describe a combined cost the same way.

  • MultiCost.accumulator is gone. Only summation was ever supported for serialization, which is what the field now does unconditionally.

  • MultiCost rejects normalization, nan_values, objective_weights, and variable_weights. It only weights and sums what its components return, so these never affected the result — set them on the component costs instead. Previously they were accepted and silently ignored.

Added

  • WeightedCost(cost, weight) pairs a component cost with its weight inside a MultiCost. It serializes to a bare {"cost": ..., "weight": ...} record, so a stored config round-trips through MultiCost.to_config().

Changed

  • ChiSquare, GaussianLogLikelihood, and DesignFunction now raise when given a field they cannot apply, rather than accepting and ignoring it:

    • ChiSquare — normalization (fixed at 1), objective_weights, and variable_weights (derived from variable_standard_deviations).

    • GaussianLogLikelihood — objective_weights and variable_weights; every variable already carries its noise scale via sigma.

    • DesignFunction — nan_values and variable_weights; design metrics are scalar per objective, so there is no per-variable axis.

  • MultiCost.to_config() normalizes every component to a {"cost": ..., "weight": ...} record regardless of how it was constructed, so the emitted config always matches what the pipeline parser reads.

  • Documented that RMSE supports scalar output only, so a MultiCost containing it needs a scalar optimizer rather than a least-squares one.

[0.17.2] - 2026-08-03

Added

  • Documented the ECM model option "butler-volmer" ("false" by default). When "true", the series overpotential gains a symmetric charge-transfer term driven by the new "Exchange current [A]" parameter, exposed as the "Charge-transfer overpotential [V]" variable. The parameter_dependencies key "i0" controls its dependencies and defaults to ("soc",) even when a mapping is supplied, so existing configs keep a state-of-charge-dependent exchange current; pass "i0": () for a constant.

Changed

  • EIS now inherits from SimulationObjective rather than FittingObjective, matching the other objectives that run a simulation and compare against measured data. The accepted arguments are unchanged.

[0.17.1] - 2026-07-29

Fixed

  • canonicalize_element_type now raises the documented ValueError when given a non-string value, instead of leaking a TypeError from the internal alias lookup.

[0.17.0] - 2026-07-28

Added

  • canonicalize_element_type and the legacy display-label → wire alias map are now owned and exported by ionworks_schema, making it the single source of truth for element-type wire aliasing. The package does not start accepting display labels — schema_class_for still rejects them — so the contract itself is unchanged.

  • LEGACY_ELEMENT_TYPE_ALIASES is exported so consumers can derive their own alias tables from the schema vocabulary instead of hand-listing it.

  • ionworks_schema.serialize with serialize_parameter_value, serialize_parameters, deserialize_parameter_value, and deserialize_parameters — the single definition of the parameter wire format, so a ParameterValues, interpolant, or other pybamm symbol round-trips identically wherever it appears in a config.

Changed

  • A ParameterValues nested anywhere in a config now serialises through the shared helper (dropping citations, flattening Scalars), and objectives route their parameters field through it, matching how a direct entry has always been written.

[0.16.0] - 2026-07-24

Added

  • Persistent model simulation_settings (mesh and solver configuration).

Changed

  • Migrated to numpy 2 and pandas 3; bumped pybamm to 26.7.1.0.

[0.15.5] - 2026-07-22

Changed

  • MSMRHalfCell: the constrain Xj method option gained a new "project" mode and its default changed from "explicit" to "project". With "project" the complete Xj groups are projected onto the bounded simplex so the fitted fractions sum to exactly 1, whereas the previous "explicit" default applied a soft equality constraint that could drift. Configs omitting this option now use "project" (#1304).

[0.15.4] - 2026-07-20

Changed

  • Raised the pydantic dependency floor from >=2.12.5 to >=2.13.4 (#1284).

[0.15.3] - 2026-07-16

Changed

  • Documentation only: expanded the ECM docstring to document the new options keys for throughput-based degradation — "capacity" and "resistance scale" ("constant" or "function"), and the degradation inputs ("Capacity throughput [A.h]", "Time [s]") supplied to a degradation function (#1235).

[0.15.2] - 2026-07-14

Changed

  • Documentation only: clarified which simulation_kwargs keys the EIS objective honors — only the mesh/discretisation kwargs (var_pts, submesh_types, geometry, spatial_methods) are applied, so an EIS objective can share a simulation_kwargs dict with a CurrentDriven / Pulse objective in the same fit without error (#1126).

[0.15.1] - 2026-07-14

Changed

  • Documentation only: clarified the to_config() serializer and the runtime-object guard in the README and package docs (#1078).

[0.15.0] - 2026-07-13

Breaking changes

  • Dropped support for Python 3.10; the minimum supported version is now Python 3.11 (#1174).

[0.14.0] - 2026-07-08

Added

  • interpolant_lossless option on the CurrentDriven and Pulse objectives: when True, the measured current samples are used directly for the interpolant (reproducing the input exactly) instead of being compressed within interpolant_atol / interpolant_rtol (#1104).

Removed

  • solver_max_save_points option on CurrentDriven and Pulse, which is no longer supported (#1104).

[0.13.1] - 2026-07-07

Added

  • Parameter-estimator and optimizer schemas (Nested, BayesianOptimization, CMAES, PSO, SOBER, TuRBO, XNES, DifferentialEvolution, GridSearch, and more), so least-squares fitting configurations that select an optimizer are validated at construction time (#1023).

[0.13.0] - 2026-06-30

Added

  • data_fit.ArrayDataFit schema for fits that run independently at each value of an independent variable and return the fitted parameter as a 2xN array (e.g. diffusivity vs. stoichiometry, parameter vs. temperature).

[0.12.0] - 2026-06-26

Added

  • Material is now strictly validated, rejecting unknown fields and enforcing per-field types (#980).

  • Priors, distributions, and samplers are now modelled as discriminated unions, so invalid combinations are caught at construction time (#978).

Changed

  • All 1-D interpolant calculations now accept "pchip" as an interpolator option (#1044).

  • Pipeline.elements is now deeply validated against the contract, surfacing nested configuration errors earlier (#981, #982).

[0.11.0] - 2026-06-25

Breaking changes

  • Removed num_workers, parallel, and max_batch_size from DataFit, and async_mode from AskTellOptimizer. Parallelism is now determined by the execution engine rather than these schema fields. Because the schema forbids unknown fields, constructing a model with a removed field (e.g. DataFit(num_workers=...)) now raises a validation error. Stored configs carrying the removed fields are migrated automatically when parsed, so no action is needed for existing saved configurations (#949).

  • The cost field on DataFit and objectives no longer accepts a bare cost-name string (e.g. cost="RMSE"). Pass a cost schema instance (iws.costs.SSE()) or a config dict ({"type": "SSE"}) instead (#1015).

  • Objectives are now validated against a discriminated union at the schema gate: each objective carries a type tag (e.g. "CurrentDriven", "CycleAgeing") and unknown objective types or fields are rejected rather than silently accepted. Objects built directly (iws.objectives.X(...)) are unaffected (#962).

Added

  • objective_parallelism ("auto"|"on"|"off") on DataFit controls objective-level parallelism. Defaults to "auto" (#949).

[0.10.0] - 2026-06-16

Added

  • GITTModel: a diffusion-only schema for fitting solid diffusivities (and the lumped ohmic resistance) to GITT or pulse-relaxation data (#904).

  • dQ/dU outputs on ElectrodeBalancing: new dQdU cutoff / dU/dQ cutoff options and the "Differential capacity [Ah/V]" output (with masked-axis siblings "Voltage [V] (dQdU)" / "Capacity [A.h] (dQdU)") so weighted costs (e.g. Wasserstein) can compare incremental-capacity curves (#859).

  • calculation_structure field on cost / objective-function schemas (e.g. SSE): an explicit objective→variable scoping map (objective name to the list of variable names to compute, or null for all). Use it to keep a per-variable cost from consuming variables that only a weighted Wasserstein should, such as model-axis dQ/dV arrays whose model and data lengths differ by construction (#953).

  • dQdU model axis option on ElectrodeBalancing: additionally emit dQ/dV on the model’s own full-window voltage axis ("Differential capacity [Ah/V] (model axis)" / "Voltage [V] (model axis)") so a weighted cost can position-shift, aligning dQ/dV peaks in voltage rather than on the data grid (#953).

Deprecated

  • objective_names on cost / objective-function schemas — a flat list of objective names the cost applies to. Use calculation_structure instead; specifying both raises a validation error (#953).

Fixed

  • A bare pandas/polars DataFrame passed to a data field (objective data_input, OCPDataInterpolant.data, Arrhenius calculations) now serializes wrapped as {"data": <columns>}, matching what the server parser expects. Previously it serialized to a bare column dict and the server rejected it with “Required field ‘data’ missing”, forcing callers to hand-wrap as {"data": df}. String paths and already-wrapped dicts are unaffected (#1005).

[0.9.0] - 2026-06-10

Added

  • Bayesian Optimization, TuRBO, and SOBER optimization algorithms (#727).

  • SimplePipeline schema for single-datafit / single-validation runs, with accompanying documentation (#658).

  • solve_kwargs on objectives — a generic mapping forwarded to sim.solve (#821).

Changed

  • store_first_last is now auto-enabled for CycleAgeing metrics that only need the first/last cycle (#828).

  • CycleAgeing objective now supports experiment='from data' (#834).

  • CycleAgeing.simulation_kwargs documents experiment_model_mode, which defaults to "unified" whenever an experiment is supplied (#862).

[0.8.2] - 2026-06-05

Changed

  • Documented the skip_objective_callbacks data-fit option, which skips capturing initial/final per-objective fit results for performance (#765).

  • Documented that simulation_kwargs on simulation objectives may include solver_kwargs to tune the auto-built solver (#776).

[0.8.1] - 2026-05-29

Removed

  • Dropped the unused numpy runtime dependency (#752).

[0.8.0] - 2026-05-28

Added

  • costs.Wasserstein now supports a weighted point-cloud mode for comparing sparse experimental data against dense simulation outputs (#733).

  • MSMRFullCell data-fit objective now exposes dQ/dU (incremental capacity analysis) output alongside the existing voltage curves (#733).

  • DirectEntry now accepts a pybamm.ParameterValues object directly, serializing callable entries to symbolic JSON automatically (#742).

[0.7.0] - 2026-05-19

Breaking changes

  • Renamed maxiters to max_iterations in DataFit.options to unify optimiser kwargs across the stack. Update any configs or call sites that set options={"maxiters": ...} to use options={"max_iterations": ...} (#655).

Added

  • costs.Wasserstein error metric for data-fit objective functions (#679).

[0.6.0] - 2026-05-12

Breaking changes

  • Renamed direct_entries.AverageOcp to direct_entries.AverageOCP to match the project-wide OCP capitalisation (OCPHalfCell, OCPDataInterpolant, OCPMSMRInterpolant). Update any imports of AverageOcp.

  • Removed the opaque distribution placeholder field from the stats.Distribution base class. Concrete subclasses (Normal, LogNormal, Uniform, …) never used it, and to_config() continues to emit "distribution": "<ClassName>" unchanged, so configs round-trip identically.

Improved

  • Docstrings on the public schema surface re-written for non-technical users. to_config() is now consistently described as the method that builds the dict you submit through ionworks-api.

  • _types placeholder classes for optional dependencies (polars, ionworksdata) simplified to plain sentinel classes instead of a nested module-impersonation wrapper.

  • Added numpy-style Parameters blocks to Pipeline, library.Material, and direct_entries.DirectEntry so every public schema class surfaces its fields in help() / IDE hovers / Sphinx (#634).

  • Fixed LaTeX math rendering in calculations docstrings — four classes (Arrhenius / standard DiffusivityFromMSMR{Data,Function}) switched to raw strings so \frac no longer renders as rac (#634).

  • Renamed footnote references on DiffusivityFromPulse and ElectrodeSOH from the anonymous [1]_ to named [Wang2022]_ and [Mohtat2019]_ so they don’t collide under docutils (#634).

  • Schema docs site live at https://packages.docs.ionworks.com/ionworks-schema/ (vanity URL: https://schema.docs.ionworks.com/) (#634).

[0.5.0] - 2026-05-11

Added

  • Schema gap fixes: new Constraint, Penalty, *Options (CMAES/PSO/DE/XNES), LatinHypercube, and Uniform classes to match what pipeline already supports (#509).

  • Sphinx documentation skeleton with autodoc + per-submodule reference pages and intersphinx cross-links to ionworkspipeline (#509).

  • Field(description=...) enrichment across ~40 classes in objectives, data_fit, direct_entries, costs, parameter_estimators, stats, parameter, library, regularizers, distribution_samplers, plus top-level Pipeline and Validation (#509).

Changed

  • Uniform now lives only in distribution_samplers (resolves the previous ambiguity with iws.Uniform) (#509).

[0.4.0] - 2026-04-30

Breaking changes

  • Cost schema restructure with correctness fixes. Existing pipeline configs that reference the old cost shape will need to be updated to match the new structure.