> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ionworks.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 2026 07 06

<Update label="July 6, 2026" description="ECM fitting with regularization and per-cell nominal capacities, ArrayDataFit through the JSON config path, and near-instant measurement deletion">
  ## ECM fitting: regularization and per-cell capacities

  Studio's ECM fit adds two options. A **regularization** setting smooths
  the fitted parameters, and a **per-measurement capacity** lets you set
  a known nominal capacity for each measurement in a fit that spans
  several measurements of the same cell. Capacity fitting is now opt-in,
  and each fitted measurement reports its own capacity.

  ## `ArrayDataFit` through the JSON config path

  `iws.ArrayDataFit` — fitting the same model independently at each value
  of an independent variable (e.g. diffusivity vs. stoichiometry from
  GITT / pulse data, or a parameter vs. temperature) — is now a
  first-class `element_type: "array_data_fit"` end to end. The library
  and schema already supported it, but the config path (the only surface
  the production API sees) previously collapsed it into a plain
  `DataFit`. Array fits now round-trip through config, schema, parser,
  executor, and results serialization, and Studio renders the array-
  valued fitted parameters with a per-parameter scatter view reachable
  from the parameter editor.

  <AccordionGroup>
    <Accordion title="Studio">
      **Improvements**

      * Cell measurement deletion is now near-instant. Logfire traces showed
        `DELETE /cell_measurements/{id}` averaging 10.3s (max 20.2s), with
        \~100% of the latency in a single recursive `list` of the
        measurement's storage folder. The per-measurement bucket layout is
        deterministic, so the file set is now derived from the DB record and
        removed in a single batched call. The recursive list stays for the
        org-wide sweep, where it's genuinely needed.
      * Missing or empty `steps.parquet` files on a measurement now surface
        as a typed 422 `MEASUREMENT_DATA_MISSING` with a re-upload prompt in
        the UI, distinct from transient storage failures (which get a Retry
        button). Upload validation also rejects empty step sets, and the
        upload rollback cleans up orphaned storage files.
    </Accordion>

    <Accordion title="Pipeline">
      **Improvements**

      * `initial_guess_sampler` on `iws.DataFit` accepts `LatinHypercube` or
        `Uniform` explicitly, and unknown sampler / distribution / prior
        names and stray keys are now rejected at submission time with a
        clear `ValidationError` instead of a later runtime crash.

      **Fixes**

      * Configuring an `ArrayDataFit` with a non-number-like `objectives`
        key (the reported bug) now surfaces as a `UserConfigurationError`
        routed to `CONFIGURATION_ERROR` — the message is shown, no Sentry
        page — instead of the opaque "An unexpected error occurred" path.
        Same treatment applied to sibling user-config validation sites
        reachable during construction / parse: bad `Material` inputs,
        non-`Transform`/`Parameter` in `Transform.__init__`, a non-dict
        `Pipeline.elements`, and cost-setter type checks on parameter
        estimators.
      * Continued sweep of \~50 more bare `ValueError` raises reclassified
        as `UserConfigurationError` / `ModelError` /
        `ProtocolConfigurationError` across the data-fit, optimizer,
        sampler, metrics, and transform code — user-correctable mistakes
        surface with an actionable message and no on-call page.
    </Accordion>

    <Accordion title="Python API">
      **Improvements**

      * `client.ecm.fit(...)` now accepts a `regularization` option and a
        per-measurement `capacity` on `FitMeasurementRequest` (set on all
        measurements or none); `FitResults.capacity_Ah` reports one value
        per fitted measurement.
      * Submitting an `array_data_fit` element via the JSON config path now
        round-trips end to end (schema → parser → pipeline → results), so
        API clients get the same first-class support the library object
        path already had.

      **Fixes**

      * Documentation examples fixed against the real API surface: the
        resubmit endpoint is `POST /jobs/{pipeline_id}/resubmit` (the
        documented `/pipelines/{pipeline_id}/resubmit` does not exist and
        would 404); the `Model` list response has no `model_type` /
        `config` field (only `client.model.get(id)` returns it);
        `model.create` config uses `type`, not `model_type`; simulate
        protocol examples use named steps + string end conditions;
        `CellMeasurementBundleResponse` is flat (`bundle.name`, not
        `bundle.measurement.name`).
    </Accordion>

    <Accordion title="Skills">
      **Improvements**

      * `run-simple-pipelines` documents the `array_data_fit` element type
        alongside the standard `data_fit`.
      * `manage-cells`: `cell_spec.create` and `create_or_get` examples now
        match `CreateCellSpecificationNested` — a `ratings` object
        (`capacity`, `voltage_min`, `voltage_max` as `{value, unit}`
        Quantities) and per-slot `cathode` / `anode` keys each holding a
        `NestedComponentInput` with a singular `material` dict. The
        previous body used `rated_capacity` / `voltage_range_dc` /
        `components: [...]` fields that do not exist on the model and
        would have failed server-side validation.
    </Accordion>
  </AccordionGroup>
</Update>
