# TODO по experimental_kinetics

## Уже сделано
- [x] Убран `unused_doc_comments` у макро-обвязок в `experiment_series_main.rs`
- [x] Добавлен `experiment_series_core.rs` как отдельный дом для ядра `TGASeries`
- [x] Добавлен `experiment_series_io.rs` и вынесена CSV/serialization-логика серии
- [x] Вынесен `ops`-блок в `experiment_series_ops.rs` и убраны дубли из главного фасада
- [x] Убраны старые приватные CSV-helper'ы из `experiment_series_main.rs`
- [x] Добавлен `experiment_series_analysis.rs` для smoothing, oneframeplot и stats-обёрток
- [x] Подключён `experiment_series_core.rs` как активный источник ядра `TGASeries`
- [x] Все `experiment_series*` файлы собраны в одну папку `experiment_series/`
- [x] Добавлен snapshot-based `undo_last` для `TGADataset`, `TGAExperiment`, `TGASeries` и GUI Reverse-хелперы
- [x] Добавлена человекочитаемая history-лента для чтения в GUI

## Проверить и закончить перенос
- [x] Сверить публичную поверхность API после выноса модулей
- [x] Прогнать `cargo check` после переноса и убедиться, что сигнатуры не сломались
- [x] Довести `analysis`-модуль до рабочей финальной формы без видимых дублей

## Наблюдения
- Большой `experiment_series_main.rs` пока остаётся фасадом и точкой сборки, но его внутренняя логика уже распадается на более узкие модули.
- Для новых модулей полезно держать короткий `//!`-док сверху и смысловые разделители внутри, как в старом файле.
- Оставшиеся предупреждения `cargo check` сейчас в основном живут в других частях репозитория и не связаны с текущим переносом `experiment_series*`.


# Experimental kinetics: TODO и технический долг

Этот файл фиксирует найденные проблемы и направления развития модулей
`experimental_kinetics` и `experimental_kinetics_gui`.

Обозначения приоритета:

- **P0** — риск неправильного научного результата или повреждения данных.
- **P1** — нарушение доменных инвариантов, нестабильный API или существенный риск ошибок.
- **P2** — архитектурный долг, сложность сопровождения и неполное тестирование.
- **P3** — чистка, документация и улучшение качества кода.

## P0: корректность данных и вычислений

- [x] Учтена единица времени при вычислении производных в `derive_rate` и `derive_rate0`.
      Теперь результат маркируется в соответствии с единицей временной колонки, а не всегда как `/s`.
- [x] Проверен порядок и единицы в `apply_golden_pipeline`: pipeline переводит секунды в часы
      до вычисления `dT/dt`, `dalpha/dt` и `deta/dt`, а производные получают метаданные
      в соответствии с часовой шкалой времени (`K/h`, `/h`).
- [ ] Исключить потерю выравнивания строк в `TGADataset::materialize`.
      Независимый `into_no_null_iter()` для каждой колонки может вернуть векторы разной длины
      и сопоставить значения из разных строк.
- [ ] Добавить единую проверку перед численной материализацией: одинаковая длина колонок,
      отсутствие недопустимых `null`, конечность значений, монотонность сетки.
- [x] Проверяются физически допустимые единицы при `bind_time`, `bind_temperature` и `bind_mass`;
      GUI показывает только контекстные варианты, а бэкенд отвергает неподходящие `Unit`.
- [ ] Проверять диапазон и направление conversion-колонок перед построением
      `ConversionGrid` (`0 <= alpha/eta <= 1`, монотонность, отсутствие повторов и NaN).
- [x] Проверена семантика `alpha` и `eta` во всём API и закреплён единый контракт:
      `alpha` = relative mass `m/m0`, `eta` = conversion `1 - alpha`,
      а типы, комментарии и подписи приведены к этой схеме там, где берётся
      производная conversion или dimensionless mass.
- [x] Проверена природа результата `derive_dimensionless_rate`: для `alpha` и `eta`
      размерность одинаковая, а различие остаётся только в доменной семантике
      и знаке производной.
- [x] Проверены граничные значения центральной разности: для производной крайние точки
      естественно теряются, поэтому `null` на первой и последней строках и последующее
      срезание краёв через `trim_null_edges` считаются нормальным поведением.

## P1: доменная модель одного эксперимента

- [ ] Сделать `TGASchema` единственным источником истины для семантики колонок и исключить
      рассинхронизацию между `columns[*].nature` и полями `time`, `mass`, `eta` и т. д.
- [ ] В `bind_time`, `bind_temperature` и `bind_mass` обновлять не только unit и binding,
      но и `ColumnMeta::nature`.
- [ ] В `bind_column` проверять, что колонка действительно существует в `LazyFrame`;
      сейчас можно создать metadata binding для отсутствующей колонки.
- [ ] В `TGASchema::update_schema` и `drop_schema_record` обрабатывать также `E` и `R2`.
- [ ] Убрать небезопасные предположения `TGASchema::from_columns` о наличии минимум трёх
      колонок и совпадении длины `names`/`units`.
- [x] Развести `Unit::Unknown` и `Unit::Dimensionless` в CSV-представлении:
      сейчас оба сериализуются как `-`, а обратно читаются как `Dimensionless`.
- [x] Расширить систему единиц или ввести размерности: минуты, K/min, mg/min и производные
      сейчас невозможно выразить без неоднозначности.
- [ ] Добавить валидацию уникальности имени при создании/переименовании колонки.
- [ ] Определить политику перезаписи существующей колонки для `with_column_expr`,
      `add_column_from_vec`, фильтров и производных.
- [x] Все операции, изменяющие frame или schema, пишут согласованную запись в History.
      Проверены `bind_column`, `drop_nulls` и операции импорта; лог истории уже читается в GUI.
- [x] Определена практическая семантика `OperationRecord::reversible`:
      `Expr` сам по себе не хранит снапшот, а откат реализован отдельной undo-машиной.
- [ ] Заменить потребляющий API с постоянным клонированием `TGADataset` там, где безопаснее
      и дешевле использовать контролируемую мутацию или транзакционное преобразование.
- [ ] Возвращать детерминированный порядок колонок вместо порядка ключей `HashMap`.
- [ ] Удалить `println!` из библиотечного кода; использовать `log` и настраиваемые уровни.

## P1: серия экспериментов и сериализация

- [x] Запретить или явно обработать повторяющиеся `ExperimentMeta::id`.
      Теперь `push` и `set_experiment_id` отклоняют дубликаты, а пересборка индекса больше не молчит.
- [x] Сделать `drop_experiment(index)` возвращающим `Result`, чтобы неверный индекс не вызывал panic.
- [x] Заменить `TGADomainError::NotImplemented` в `drop_experiment_by_id` на содержательную ошибку.
- [ ] Исключить клонирование всего `TGAExperiment` в `transform_by_id`/`try_transform_by_id`
      либо документировать стоимость и атомарность такого подхода.
- [ ] Инкапсулировать `experiments` и `exp_map`, чтобы внешний код не мог нарушить их согласованность.
- [ ] При series CSV roundtrip сохранять и восстанавливать `ColumnNature`.
- [ ] При series CSV roundtrip сохранять binding `R2`; сейчас сохраняется `E`, но не `R2`.
- [ ] Добавить версионирование и тесты миграции формата `#META`, включая экранирование id,
      комментариев, табуляций, переводов строк и пустых серий.
- [ ] Проверить single-dataset CSV roundtrip: bindings, nature и origin должны либо сохраняться,
      либо потеря метаданных должна быть явно частью формата.
- [ ] Убрать временный файл из `from_csv_series` и читать CSV-часть через поток/буфер.
- [ ] Определить поведение объединения опытов с разными длинами, схемами и единицами до создания
      `UnitedDataset`.

## P1: численные и кинетические методы

- [ ] Централизовать проверку требований метода: число опытов, режим эксперимента,
      heating rate/isothermal temperature, обязательные природы колонок и единицы.
- [ ] Проверять одинаковую длину всех векторов внутри `ExperimentData`, как обещано документацией.
- [x] Проверять сортировку и уникальность conversion перед линейной/сплайн-интерполяцией.
- [x] Защитить `compute_dt_matrix` от сеток длины меньше двух и неположительных `dt`.
- [x] Проверять `segments >= 2`, конечность и корректность ручного диапазона в
      `ConversionGridBuilder`.
- [x] Защитить расчёты `1/T`, `ln(rate)` и другие преобразования от нулей,
      отрицательных значений, NaN и бесконечностей.
- [ ] Унифицировать представление результатов методов (`Ea`, предэкспонента, `R2`,
      доверительные интервалы, диагностические данные).
- [ ] Добавить оценку неопределённости и устойчивости результатов к выбору диапазона conversion,
      сглаживанию и числу точек сетки.
- [ ] Добавить эталонные тесты на опубликованных или аналитически воспроизводимых наборах
      для Friedman, KAS, OFW, Starink, Vyazovkin, Kissinger, Criado и combined analysis.
- [ ] Отделить экспериментальные/альтернативные реализации (`kinetic_methods2`,
      `Criado2`, `experiment_series2/3`) от стабильного публичного API или переименовать их.

## P2: preprocessing и RustedSciThe

- [ ] Описать явную границу ответственности: KiThe отвечает за доменную семантику и pipeline,
      RustedSciThe — за численные примитивы.
- [ ] Обернуть ошибки Savitzky-Golay, LOWESS и сплайнов RustedSciThe в содержательные
      `TGADomainError` с параметрами операции и именами колонок.
- [ ] Валидировать параметры фильтров до вызова backend: размер окна, степень полинома,
      число точек, число узлов, диапазон `frac`, минимальную длину данных.
- [ ] Унифицировать правила обработки краёв и `null` для всех фильтров.
- [ ] Зафиксировать контракт resampling: какая колонка является сеткой, сохраняются ли исходные
      колонки, как назначаются unit/nature/origin результирующим колонкам.
- [ ] Устранить дублирование методов `*_as`/без `*_as` через общий внутренний helper.
- [ ] Добавить regression-тесты совместимости с используемой версией RustedSciThe.
- [ ] Решить судьбу локального `LSQSplines2.rs`: удалить, подключить или явно пометить
      как архивную/экспериментальную реализацию.

## P2: GUI и синхронизация состояния

- [ ] Сократить дублирование фасадов `TGADataset -> TGAExperiment -> TGASeries -> PlotModel`.
- [ ] Формализовать синхронизацию `TGASeries` и `PlotCurve`: сейчас обновление sampled-кривых
      распределено между history, флагами и ручными вызовами.
- [ ] Исключить stale plots после переименования/удаления колонок, удаления опыта и смены id.
- [ ] Убрать `unwrap()` из пользовательских GUI-сценариев, особенно для calibration settings,
      последнего опыта и обязательных derived-колонок golden pipeline.
- [ ] Сделать ошибки `TGADomainError` и `TGAGUIError` реализующими `Display`/`Error`
      и показывать пользователю содержательные сообщения.
- [ ] Разделить крупный `model_handlers.rs` по сценариям: data management, preprocessing,
      plotting, kinetic methods и result publishing.
- [ ] Удалить видимые заглушки `TODO: Implement Criado master curve analysis`
      и `TODO: Implement model fitting` либо скрыть незавершённые действия.
- [ ] Исправить повреждённую кодировку русских комментариев и строк интерфейса.
- [ ] Уточнить границу между встроенным `egui_plot` и `kithe_plot`, чтобы не поддерживать
      два несогласованных пути визуализации.
- [ ] Добавить end-to-end GUI-тесты основных пользовательских маршрутов:
      импорт, binding, preprocessing, построение серии, запуск метода, экспорт результата.

## P2: provenance колонок и качество фильтрации

- [ ] Вынести provenance колонок в отдельный модуль и хранить цепочку преобразований рядом с `TGADataset`.
- [ ] По умолчанию для smoothing/filtering создавать новую колонку, а in-place режим оставить как совместимый вариант.
- [ ] Прокинуть provenance и quality report в GUI table manager, чтобы над каждой колонкой была видна история преобразований.
- [ ] Добавить synthetic-data сценарии с шумом и выбросами для сравнения качества сглаживания не "на глаз", а по метрикам.
- [ ] Проверить, что цепочка `RAW -> SG -> LOWESS -> ...` не теряется при повторных преобразованиях и `undo`.

## P2: тестирование и инварианты

- [ ] Собрать общие проверки pipeline в reusable test helpers вместо повторяющихся проверок.
- [ ] Добавить property-based тесты: сохранение выравнивания строк, монотонность сетки,
      roundtrip сериализации, корректность metadata после цепочки операций.
- [ ] Тестировать данные с `null`, NaN, infinity, пустыми колонками, одной строкой,
      повторяющимся временем и немонотонной conversion.
- [ ] Добавить тесты для повторяющихся experiment id и повреждённого `exp_map`.
- [ ] Добавить тесты roundtrip всех `Unit`, `ColumnNature`, `ColumnOrigin` и bindings.
- [ ] Разделить быстрые unit-тесты, численные regression-тесты и тяжёлые synthetic/integration tests.
- [ ] Убрать тестовые модули из публичного production API или закрыть их через `#[cfg(test)]`.
- [ ] Проверить, что сборка библиотеки не компилирует ненужные тестовые генераторы и GUI harness.
- [ ] Настроить CI-матрицу минимум для `cargo fmt`, `cargo check`, unit tests и документационных тестов.

## P3: API, структура и документация

- [ ] Разбить `one_experiment_dataset.rs` на модули: errors, units, schema, history, I/O,
      materialization и core dataset.
- [ ] Разбить `experiment_series_main.rs` на core series, persistence, transform facade
      и metadata.
- [ ] Удалить массовые шаблонные комментарии вида “API method in the facade” и заменить
      их документацией реального контракта, ошибок и побочных эффектов.
- [ ] Привести имена к Rust conventions (`dT_dt`, `E`, `R2`, `from_C_to_K` и подобные).
- [ ] Устранить дублирующие или неоднозначные варианты ошибок (`NoDimensionless`,
      `AlphaNotFound`, `EtaNotFound`) после фиксации терминологии.
- [ ] Добавить публичную схему рекомендуемого TGA pipeline с единицами на каждом шаге.
- [ ] Документировать момент перехода `LazyFrame -> DataFrame -> Vec/ndarray` и стоимость collect.
- [ ] Определить стабильную публичную prelude/API-поверхность experimental kinetics.
- [ ] Пометить экспериментальные API как нестабильные и зафиксировать правила semver.
- [ ] Добавить архитектурную диаграмму потока:
      `TGADataset -> TGAExperiment -> TGASeries -> UnitedDataset -> KineticDataView -> ConversionGrid`.

## Ближайший рекомендуемый этап

- [ ] Сначала исправить размерности производных и безопасную materialization.
- [ ] Затем закрепить инварианты `TGASchema` и терминологию `alpha/eta`.
- [ ] После этого стабилизировать id/index серии и полный metadata roundtrip.
- [ ] Только затем сокращать фасады и перестраивать GUI, опираясь на стабильный domain API.

## Текущая итерация: время и сортировка
- [x] Добавлен `TimeMonotonicityReport` для активной time-колонки: null / NaN / inf / duplicate / decreasing.
- [x] `monotony_of_time_check` сохранён как тонкая совместимая обвязка над новым отчётом.
- [x] `sort_by_bound_time` переведён на lazy sort Polars без лишней materialization.
- [x] Сортировка по времени протянута через `TGAExperiment`, `TGASeries` и GUI.
- [x] Кнопка `Check time monotonicity` в GUI пишет человеческую диагностику.
- [x] Кнопка `Sort by time` сортирует эксперимент и пересобирает живые графики.
- [x] Добавлены тесты на структурированный отчёт времени, отказ при invalid time и сохранение row alignment после сортировки.

## Текущая итерация: materialize
- [x] `TGADataset::materialize` теперь отказывается молча терять `null`-значения в grid/колонках.
- [x] `materialize_vertical_column_by_name` и `materialize_struct_field_by_name` тоже проверяют `null` перед сборкой числовых векторов.
- [x] Добавлен тест на отказ materialize при `null` вместо тихого укорочения вектора.
- [x] Базовые `bind_*`-операции переведены на mutable-путь без лишнего клонирования `TGAExperiment`
      на уровне `TGASeries`: `bind_time`, `bind_temperature`, `bind_mass`, `bind_column`.
- [x] `TGASeries::transform_by_id` переведён на временное извлечение эксперимента из вектора
      без `clone`; consuming-операции теперь не копируют весь `TGAExperiment` заранее.

## Текущая итерация: fitting

- [x] Закрепить контракт `fitting.rs` как численного слоя fitting:
      `Fit` получает два вектора `x/y`, выбирает модель `FittingModelName`, запускает LM или VARPRO,
      возвращает карту коэффициентов, `R2` и умеет вычислять `fitted_y` через `evaluate_solution`.
- [x] Добавить доменный wrapper для fitting одного эксперимента в `TGASeries`.
      Вход: `experiment_id`, `x_col`, `y_col`, `FittingModelName`, настройки tolerance/max_iter/initial_guess
      и опциональное имя выходной колонки.
      Важно: fitting работает только внутри одного эксперимента, без смешивания колонок из разных опытов.
- [x] Для входа использовать существующую материализацию колонок одного эксперимента.
      Базовый путь: найти `TGAExperiment` по id и вызвать `dataset.materialize(x_col, &[y_col])`;
      при необходимости добавить более удобный helper, который возвращает согласованные `Vec<f64>` для пары колонок.
      Проверить отсутствие потери выравнивания строк, `null`, NaN, infinity и несовпадения длины `x/y`.
- [x] Для выхода использовать `TGASeries::add_column_from_vec`, который уже оборачивает
      `TGADataset::add_column_from_vec`.
      Имя по умолчанию: `fit_<model>_<y_col>`, например `fit_linear_mass`.
      При конфликте имени использовать существующую политику уникальности или вернуть понятную ошибку.
- [x] Определить metadata для fitted-колонки.
      Единица fitted-y должна наследоваться от исходной `y_col`.
      `ColumnOrigin = NumericDerived`.
      `ColumnNature`: временно можно использовать `Unknown`, но лучше ввести явную природу вроде
      `FittedCurve`/`FittedY`, чтобы Column Manager и export не теряли смысл результата.
      Provenance должен хранить модель, x/y источники, коэффициенты, `R2`, tolerance/max_iter и operation id.
- [x] Добавить структуру результата fitting на уровне KiThe, например `FitColumnResult`:
      experiment id, x/y/output column names, model name, coefficients in display order,
      `R2`, used method (`LM`/`VARPRO`), iteration/settings summary.
      Она нужна и тестам, и GUI pretty-print таблице.
- [x] Добавить тесты интеграции с `testing_mod.rs`:
      одноэкспоненциальный isothermal experiment -> `FittingModelName::DecExp`;
      двухкомпонентный isothermal experiment -> `FittingModelName::TwoExp`.
      Проверки: fitted column появилась в нужном эксперименте, длина совпадает с исходным dataframe,
      коэффициенты близки к синтетическим параметрам, `R2` высокий, fitted curve материализуется обратно.
- [x] Для двух экспонент учитывать неидентифицируемость порядка компонент.
      Тест должен сравнивать пары `(amplitude, rate)` как неупорядоченное множество или сортировать по rate,
      иначе корректный fit может падать из-за перестановки экспонент.
- [x] Расширить негативные тесты:
      неизвестный experiment id, отсутствующая x/y колонка, пустые данные, несовпадающие длины,
      конфликт имени выходной колонки, неверная длина initial_guess.
      Также покрыто: NaN/inf во входе.
- [x] Подключить GUI в `Kinetic Methods -> Fit Model` вместо текущей заглушки.
      Окно должно содержать выбор эксперимента, два выпадающих списка `x` и `y`,
      выбор модели, optional output name, поля tolerance/max_iter и initial guess.
- [x] В GUI показывать результат fitting таблично:
      коэффициент / значение, `R2`, выбранный backend, имя созданной fitted-колонки.
      После успешного fit автоматически добавить plot `fitted_y vs x` и обновить Column Manager.
- [x] Добавить GUI smoke/scenario tests:
      меню `Kinetic Methods -> Fit Model` открывается,
      выпадающие списки заполняются колонками выбранного эксперимента,
      synthetic one-exp dataset можно fit-нуть и получить новую fitted-колонку/кривую.
      Покрыто: egui-smoke открытия окна и `PlotModel` scenario fit -> новая fitted-колонка и видимая кривая.
