KiThe 0.3.9

A numerical suite for chemical kinetics and thermodynamics, combustion, heat and mass transfer,chemical equilibrium, chemical engeneering
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
# GUI BVP Technical TODO

Scope: `src/gui/` with emphasis on the combustion BVP menu and its tests.
The current BVP screen still behaves like a generic document editor, while the reactor
solver backend has grown into a much richer typed configuration surface.

## P0: expose the new BVP solver surface in the GUI

- [x] Split the BVP menu into clear sections for physics, solver backend, initial guess, and postprocessing.
  Why:
  the current UI mixes reactor physics and solver-engine knobs in one raw document editor, which makes the new API hard to discover.

- [x] Add first-class controls for the modern solver backend settings.
  Required fields:
  - `generated_backend`
  - `matrix_backend`
  - `symbolic_backend`
  - `aot_c_compiler`
  - `aot_build_policy`
  - `aot_build_profile`
  - `aot_compile_preset`
  - `aot_execution_policy`
  - `banded_linear_solver`
  - `refinement_steps`
  Why:
  the new combustion solver API supports lambdify and AOT execution, but the GUI still only exposes the old `scheme/method/strategy`-style fields.

- [x] Make the default visible and explicit in the UI.
  Target default:
  `Lambdify + AtomView + Banded`
  Why:
  users should see the production default immediately instead of guessing from template comments.

- [x] Remove outdated solver wording from the BVP help text.
  Current stale concepts:
  - `Dense` as a solver method
  - solver settings described only as tolerances and bounds
  - backend choices not shown in the help map
  Why:
  the UI should describe the real solver contract, not the old simplified one.

## P1: keep the GUI and the typed parser aligned

- [x] Update the BVP template to use the new canonical solver keys where appropriate.
  Why:
  the template is still the main entry point for many users, so it should mirror the typed solver API instead of hiding it.

- [x] Keep legacy documents working through compatibility aliases only.
  Why:
  old task files still exist, but the GUI should not teach stale names as the primary path.

- [x] Add regression tests for the BVP menu document generation.
  Cover:
  - default template contents
  - round-trip parsing of the new solver backend fields
  - legacy solver documents still loading
  - `gui_plot` / postprocessing behavior for solved BVP runs
  - `egui_kittest`-driven interaction checks for the combustion/BVP menu so we do not rely on manual clicking

- [x] Add story tests for the combustion screen presets and backend mode switching.
  Cover:
  - default BVP preset
  - AOT preset
  - sparse compatibility preset
  - validation of missing or malformed backend fields

- [x] Show species composition sections as first-class BVP UI instead of treating them as legacy raw document content.
  Why:
  per-species atomic composition is part of the reactor physics contract, not a compatibility-only edge case.

- [x] Surface `RUN CALCULATION` feedback directly in the GUI.
  Why:
  solver failures and validation problems should be visible to the user instead of disappearing into logs.

- [x] Split the solver backend UI into a mutually exclusive `Lambdify` / `AOT` selector.
  Why:
  the backend choice is not a free-form text field; the GUI should expose the actual finite set of supported execution modes.

- [x] Enforce the `Lambdify` / `AOT` choice as one coherent solver contract.
  Implemented behavior:
  - `Lambdify` sets `backend_policy: lambdify_only` and removes every AOT artifact-lifecycle field.
  - `AOT` sets `backend_policy: aot_only` and creates the compiler/build defaults only for that mode.
  Why:
  RustedSciThe supports execution selection and AOT artifact management as independent low-level settings, but the KiThe GUI deliberately presents them as mutually exclusive user modes. A Lambdify run must never compile or load an AOT artifact as a side effect.

- [x] Normalize `refinement_steps` to `usize` before handing the document to the solver.
  Why:
  the solver contract rejects floating-point values for this field, so the GUI must coerce the value into the expected typed form.

- [x] Expose grid refinement as a finite strategy selector instead of raw method keys.
  Covered strategies:
  - `pearson`
  - `grcarsmooke`
  - `twopnt`
  - `easy`
  - `doubleoints`
  Why:
  RustedSciThe accepts a short parser-supported strategy list, so the GUI should prevent invalid free-form method names and keep only one active refinement method.

- [x] Add a BVP save/read/save roundtrip regression test.
  Why:
  the GUI workflow relies on saving a configured task file and reading it back later; the generated document must therefore be parser-stable and must not emit duplicate keys or empty parser-invalid sections.

- [x] Keep advanced solver sections next to the main solver backend panel.
  Why:
  `rel_tolerance`, `strategy_params`, `adaptive_strategy`, and `grid_refinement` are solver settings, not reactor physics or species-composition data.

- [x] Replace the generic `linear_sys_method` optional editor with a typed override selector.
  Why:
  the normal value is `None`/Auto; the generic optional editor could create meaningless `Some(Float(0.0))` payloads for a field that RustedSciThe treats as `Option<String>`.

- [x] Use `refinement_steps = 5` as the KiThe BVP GUI/template default.
  Why:
  `0` remains a valid opt-out, but a small nonzero default is a better practical starting point for the banded solver route.

- [x] Replace the legacy `strategy_params.adaptive` editor with one complete adaptive-grid toggle.
  Why:
  RustedSciThe enables adaptation from the `adaptive_strategy` and `grid_refinement` sections. The GUI now creates or removes that complete contract atomically and seeds the only supported production version (`1`).

- [x] Collapse `method` and `matrix_backend` into one visible linear-algebra backend control.
  Why:
  Both fields select the same Sparse/Banded route for reactor BVP tasks. KiThe keeps both lower-level aliases synchronized for RustedSciThe compatibility without asking the user to configure the same choice twice.

## P2: polish and maintainability

- [ ] Reduce the amount of raw document editing needed for common BVP workflows.
- [x] Separate user-facing physics fields from advanced solver fields visually.
- [ ] Keep helper text and template comments in sync with the solver backend API.
- [ ] Remove dead wording that talks about the old backend model once the new controls exist.
- [x] Normalize `max_iterations` to `usize` before handing the document to the solver.

# Transport and Thermochemistry GUI Technical TODO

Scope: `transport_gui.rs`, `thermochemistry_gui.rs`, and their dedicated
`egui_kittest` regression modules. The database handlers and `SubsData` already
provide the typed calculation boundary; these screens should be thin, state-safe
clients of that boundary rather than independent implementations of the same
business logic.

Priority definitions:

- **P0**: realistic application crash or loss of the active GUI workflow.
- **P1**: potentially incorrect property source/result or misleading visible state.
- **P2**: architecture and validation debt likely to cause future regressions.
- **P3**: incomplete UX, wording, and maintainability work.

## P0: fail safely when the thermodynamic catalog cannot be loaded

- [x] Replace `ThermoData::new()` in both GUI constructors with the fallible
  `ThermoData::try_new()` path.
  Affected paths: `TransportApp::default` and `ThermochemistryApp::default`.
  Required behavior: a missing, malformed, or schema-invalid catalog produces a
  visible typed startup error and an inert calculation surface; it must not panic
  and terminate the entire GUI application.
  Done when: constructor tests inject missing/invalid catalog fixtures and prove
  that both screens remain renderable while exposing the load failure.
  Implemented: both GUI screens now build from `ThermoData::try_new()` and fall
  back to an inert empty catalog plus a visible startup error banner when loading
  fails. The dedicated GUI tests inject a synthetic catalog error and confirm that
  the screens stay alive and refuse to calculate.

## P1: use the canonical property aggregation boundary

- [x] Move transport calculation orchestration from raw handlers to `SubsData`.
  Affected paths: `perform_transport_calculation` and
  `calculate_heat_capacity_for_transport`.
  Required behavior: library priority, explicit search instructions, aliases,
  Cp lookup, molar mass, pressure, and transport calculation follow the same typed
  contract used by reactor code. The GUI must not choose the first matching thermo
  library or derive molar mass directly from an arbitrary display name.
  Done when: the GUI calculation path reads numeric values through canonical
  `SubsData` accessors and tests cover competing thermo sources, aliases, missing
  Cp, and a library name that is not itself a parseable chemical formula.

- [x] Move thermochemistry calculation orchestration to the same `SubsData`
  search and derived-value contract.
  Required behavior: explicit selection of a thermo library remains possible, but
  lookup, calculator initialization, typed errors, and numeric output no longer
  duplicate low-level handler code inside the GUI.
  Done when: NASA and NIST GUI stories use the aggregator and agree with direct
  `SubsData` results at the same temperature and units.

- [x] Invalidate dependent GUI state after every input-source mutation.
  Affected state: `selected_substance`, `calculated_*`, `search_results`, and
  `plot_window`.
  Required behavior: changing library, substance, temperature, pressure, or units
  cannot leave a result that appears to belong to the new inputs. Failed
  calculations clear the previous successful numeric snapshot.
  Done when: lifecycle tests cover success followed by library change, substance
  change, invalid input, unsupported temperature, and unit change.

- [x] Make the thermochemistry screen's visible contract match its calculations.
  Decision taken: remove pressure and Gibbs wording from this screen instead of
  pretending it computes `dG(T, P)`.
  Result:
  the visible contract now matches the actual canonical calculation path, which
  computes only `Cp`, `dH`, and `dS` from temperature.
  Done when: the chosen contract is explicit in the controls, output, and tests;
  no accepted field is silently ignored.

- [x] Fix the temperature-range window lifecycle and user-visible errors.
  Closing the window now persists, invalid ranges and calculation failures are
  rendered inside the GUI, and opening plots without a selected substance
  produces actionable feedback.
  Done when: `egui_kittest` covers open, calculate, failure, close, and reopen.
  Covered so far: missing-substance feedback is visible, and valid range
  calculation builds a ready plot snapshot instead of silently doing nothing.

- [x] Repair corrupted unit labels and settle on one encoding-safe notation.
  Affected labels include thermal conductivity, viscosity, Cp, and entropy units.
  Preferred fallback: ASCII forms such as `W/(m*K)`, `uPa*s`, and `J/(mol*K)` if
  source encoding cannot be guaranteed consistently.
  Done when: source scans contain no mojibake and widget/output tests assert the
  exact visible labels.

## P2: typed input and deterministic editor state

- [x] Introduce one shared typed condition parser for temperature, pressure, and
  temperature ranges.
  Required behavior: reject non-finite, non-positive, overflowing, and malformed
  values before entering a calculator; require `T0 < Tend`; return field-specific
  visible errors.
  Done when: table-driven tests cover zero, negative values, `NaN`, infinity,
  malformed strings, reversed ranges, and valid boundary values on both screens.

- [x] Separate editable inputs from read-only result snapshots.
  Required behavior: raw database JSON and calculated reports remain selectable or
  copyable but cannot be edited as if they were active application state.
  Done when: rendering tests distinguish input widgets from read-only result views.

- [x] Make substance lists deterministic and selection-aware.
  Required behavior: library keys are sorted, the selected substance is visibly
  selected, and changing a filter does not silently change calculation ownership.
  Done when: repeated construction produces the same ordering and interaction tests
  verify the selected row state.

- [x] Remove duplicate/dead search paths after the typed calculation migration.
  Affected code: `search_substance`, `search_substance_by_name`, raw JSON lookup,
  and the commented low-level usage blocks at the top of both modules.
  Done when: each screen has one search transition and one calculation transition,
  both documented with their state effects.
  Progress: the dead free-text `search_substance` methods and the old low-level
  example comments have been removed; the remaining live path is the selection-
  driven snapshot update through `search_substance_by_name`.
  Completed: both calculation paths now require an explicit selected substance;
  typed selection remains the only way to enter a calculation snapshot.

## P3: complete or remove decorative actions

- [ ] Implement or remove `Export Data` on both screens.
  Status: intentionally deferred for a future UX pass. We keep it visible as a
  placeholder for now, but it is not part of the current hardening work.
  Required behavior: an enabled export action writes a typed snapshot and keeps a
  persistent success/error status; an unavailable feature is visibly disabled.

- [ ] Implement or remove transport `Load from File`.
  Status: intentionally deferred for a future UX pass. We keep it visible as a
  placeholder for now, but it is not part of the current hardening work.
  Required behavior: loading uses a documented typed format and never appends a
  placeholder message that looks like completed work.

- [ ] Review module-level feature documentation after the functional migration.
  Remove claims that are not represented by working controls and keep comments
  aligned with the `SubsData` ownership boundary.

## Required transport and thermochemistry GUI test matrix

- [x] Transport picker exposes CEA and Aramco transport backends.
- [x] CEA and Aramco happy paths return positive finite transport values.
- [x] Thermochemistry picker excludes transport-only CEA records.
- [x] NASA happy path returns finite thermochemical values.
- [x] Drive library selection, substance selection, and calculation through real
  `egui_kittest` widget interactions instead of calling calculation methods directly.
- [x] Cover missing/malformed catalog startup without a panic.
- [x] Cover state invalidation after library, substance, condition, and unit changes.
- [x] Cover all non-finite and non-positive numeric input classes.
- [ ] Compare GUI results with canonical `SubsData` results for NASA, NIST, CEA,
  and Aramco scenarios.
  Note: NASA, CEA, and Aramco are covered by the new canonical comparison tests.
  NIST still needs a stable calculable fixture in the local catalog before we
  can assert the same GUI-vs-SubsData contract.
- [x] Cover plot-window lifecycle and visible range-calculation failures.
- [x] Assert exact encoding-safe unit labels and result text.

# Chemical Equilibrium GUI Technical TODO

This section defines the GUI boundary for the production chemical-equilibrium
API. The editor must consume only
`Thermodynamics::ChemEquilibrium::prelude`; legacy mutable equilibrium
orchestrators are not a GUI dependency.

The first implementation target is ideal fixed-pressure equilibrium with
explicitly declared phases at `P,T = const`. Bounded phase control and
temperature ranges are supported extensions of the same typed model. The
fixed-pressure, fixed-total-enthalpy (`P,H`) engine is now also connected
through a separate typed request path; the GUI must never simulate it by
silently substituting a temperature.

## Architectural decisions

- [x] Start the feature as focused modules instead of one large application
  file:
  - [x] `equilibrium_gui.rs`: first egui editor/application surface;
  - [x] `equilibrium_gui_model.rs`: serializable editor/document model and pure
    validation;
  - [x] `equilibrium_gui_request.rs`: the only conversion boundary from validated
    GUI values to production `ChemEquilibrium::prelude` requests;
  - [x] `equilibrium_gui_execution.rs`: transactional run gate and
    stale-result policy; background resolve/solve worker and
    immutable outcomes;
  - `equilibrium_gui_plot.rs`: equilibrium result series and adapters for both
    the existing embedded plot window and KiThePlot;
  - separate config, kittest, lifecycle, story, and plot-adapter test modules.

- [x] Introduce a versioned `EquilibriumGuiDocument` that owns only editable,
  serializable values. Keep transient catalog previews, repository handles,
  workers, plots, and accepted solver results outside the document.

- [x] Make `EquilibriumGuiConfig` a sum of typed policy blocks rather than a
  collection of booleans:

  ```text
  EquilibriumGuiConfig
  +-- problem: EquilibriumProblemSpec
  +-- inventory: EquilibriumInventorySpec
  +-- lookup: EquilibriumLookupPolicy
  +-- phase_mode: EquilibriumPhaseMode
  +-- solver: EquilibriumSolverPolicy
  +-- diagnostics: EquilibriumDiagnosticsPolicy
  +-- postprocessing: EquilibriumPostprocessingPolicy
  ```

- [x] Store physical values in canonical SI units after parsing. Editable text
  and display-unit choices belong to field drafts; validated requests must not
  contain unit-dependent strings.

- [x] Key every initial amount and result column by a phase-qualified component
  identity (phase plus exact record/substance key), never by a bare substance
  name. `gas::H2O` and `liquid::H2O` are distinct components even when their
  molecular compositions are equal.

- [x] Publish one immutable GUI-owned result snapshot per successful run.
  `EquilibriumGuiResultSnapshot` is built transactionally from accepted point
  or range outcomes, retains the source solution through `Arc`, and rejects
  empty or layout-inconsistent range payloads before publication.
  Point and range snapshots must retain conditions, canonical component order,
  physical moles, mole fractions, phase status, lookup provenance,
  conservation/acceptance evidence, backend attempt reports, optional
  equilibrium-constant validation, and optional timing. Plot windows receive
  `Arc` snapshots and never borrow mutable solver state.

- [x] Keep production defaults in the engine. The GUI expresses
  `ProductionDefault` explicitly and only construct detailed tolerances,
  cascades, or phase-control parameters when the user selects an advanced
  override. The remaining advanced override surface is tracked separately.

## Engine/API gaps discovered during GUI planning

- [x] Re-export every type required by the GUI request builder through
  `ChemEquilibrium::prelude`. In particular,
  `EquilibriumConstantValidationMode` is accepted by
  `EquilibriumSolveOptions` and is now exported through the production
  prelude; the GUI does not import an internal equilibrium path to reach it.

- [x] Give production point/range workflows a cloneable cooperative execution
  control with an optional typed progress sink. Cancellation is checked before
  lookup/formulation, between range points, before/after backend attempts, and
  from residual evaluation where the backend exposes that callback. A
  cancelled request returns typed `ReactionExtentError::Cancelled`; the GUI
  keeps the worker receiver until its terminal message and never publishes a
  partial range.

- [x] Report progress only at stable engine boundaries: repository lookup,
  formulation preparation, point start, and accepted point. The GUI renders
  the last typed event and does not invent percentages from elapsed time.
  Backend-attempt progress remains a solver-report concern until the backend
  contract exposes safe attempt callbacks.

## P0: typed document and request boundary

### P0.1 Thermodynamic problem

- [x] Model the thermodynamic constraint as an enum:
  - `FixedPT { pressure, reference_pressure, temperature }`;
  - `FixedPH { pressure, reference_pressure, target_total_enthalpy_j,
    temperature_bounds, seed }`.
  P,H uses extensive joules at the GUI boundary and validates the scalar
  bracket/seed before repository access. Its request resolves thermochemistry
  in the worker and publishes a read-only energy-contract report.

- [x] Model fixed-`P,T` temperature input as:
  - `Point { temperature }`;
  - `Range { start, end, point_count }`.
  Validate finite positive temperatures, finite positive pressures,
  `point_count >= 2`, non-equal endpoints, and both ascending and descending
  grids. Use the production `TemperatureGrid` for final validation.

- [x] Reserve an advanced postprocessing range policy independent from the
  solver grid: no resampling, or PCHIP resampling with a user-selected output
  grid/count and interpolation space. Resampling must never masquerade as
  additional solved equilibrium points. The display adapter now implements
  linear/log PCHIP, clamping, descending grids, and explicit rejection of
  single-point or non-positive log data.

### P0.2 Inventory modes

- [x] Model substance input as an enum, not as two simultaneously active
  panels:
  - `ExplicitPhases`: phase rows with typed physical state, activity model,
    exact component keys, and initial moles;
  - `ElementCandidates`: requested elements plus a typed candidate-selection
    policy.

- [x] Provide a simple explicit-species preset that creates one ideal-gas phase,
  while retaining an advanced phase editor. The simple mode is only a builder
  for the same canonical phase specification; it must not have a separate
  solving path. The typed document constructor and editor action now use the
  same explicit-phase request path.

- [x] Define the element-mode data contract as a two-stage workflow:
  1. preview deterministic candidates with selected/rejected reasons,
     temperature support, physical state, library, record key, and provenance;
  2. confirm candidate-to-phase assignments and edit initial component moles.
  Candidate discovery cannot directly launch a solve because the solver
  requires an explicit initial inventory. The GUI now runs local-catalog
  discovery in a background worker and renders an immutable audit projection;
  assignment controls now exist and preserve the selected record's library
  provenance; the candidate table now also edits assigned initial amounts.
  Manual inclusion toggles beyond explicit assignment remain.

- [x] Keep the candidate preview as derived state tied to the document
  fingerprint. Any change to elements, library policy, state filters,
  temperature interval, or candidate limit makes the preview stale; the
  fingerprint gate prevents it from being shown as current.

- [x] Expose candidate selection controls already supported by the engine:
  exact element set versus subset-of set, allowed physical states,
  temperature-coverage filter, deterministic candidate limit, and explicit
  candidate-to-phase assignments. Exact/subset, state filters, temperature
  bounds, element rows, and candidate limits are now editable in the GUI;
  candidate-to-phase assignment is now wired to the document and pins the
  selected library into the production lookup instructions. Manual inclusion
  toggles remain; assignment amounts and pinned provenance are editable and
  visible. Do not infer phase activity models from catalog metadata.

- [x] Validate unique phase IDs, unique phase-qualified components, finite
  non-negative initial moles, at least one positive amount, and complete
  candidate phase assignment before constructing a production request.

### P0.3 Library lookup

- [x] Model lookup as:
  - `DefaultPolicy`, using canonical repository defaults;
  - `ExplicitPolicy`, with ordered priority libraries, permitted libraries,
    explicit record instructions, and NIST fallback policy.

- [x] Populate library choices through the repository/API rather than a
  hard-coded GUI list. Preserve library order where it represents preference,
  but sort unordered catalog display lists deterministically. The editor now
  loads the local catalog in a background worker, normalizes the choices, and
  uses them to seed ordered priority/permitted entries; manual canonical-name
  editing remains available when the catalog is not loaded.

- [x] Treat library selection and physical phase as separate dimensions.
  Selecting `NASA_cond` does not itself mean “solid”, and requesting a liquid
  phase does not silently rewrite a substance name.

- [x] Display lookup/build provenance and failures per phase-qualified
  component. A partially resolved system must not become runnable.

### P0.4 Solver and phase-control policies

- [x] Model nonlinear backend selection as:
  - `ProductionDefault`;
  - `Single(SolverBackendChoice)`;
  - an advanced ordered custom cascade, if exposed.
  Include all supported RST backends and retained legacy LM/NR/TR numerical
  fallbacks, using stable display names mapped in one place.

- [x] Add typed advanced overrides for tolerance, maximum iterations, scaling,
  cascade budget, and trace-species seed policy. Defaults remain unset so the
  engine owns canonical production values.
  Progress: tolerance, iteration, scaling, trace-species seed overrides, and a
  user-owned ordered backend cascade are typed and validated. The GUI exposes
  add/remove/reorder controls and the request boundary maps the cascade to the
  engine policy, including the optional validated cascade budget. Scaling now defaults to the engine's stable `false` value;
  enabling it remains an explicit advanced choice after the real water/ice
  story exposed its sensitivity. The budget remains absent unless explicitly
  enabled by the user.

- [x] Model phase behavior as:
  - fixed declared phases;
  - bounded phase control with `PhaseControlPolicy`.
  Advanced controls include initial active phases, phase epsilon, outer-loop
  budget, and explicit or temperature-scaled hysteresis.

- [x] Enforce capability constraints in validation:
  multi-start is available only for the fixed active-set `P,T` workflow;
  range continuation and phase-control policies use their production typed
  contracts; unsupported combinations are disabled with a reason rather than
  silently downgraded. The GUI currently exposes no multi-start control, so it
  cannot be selected accidentally; the engine request boundary rejects it for
  ranges and bounded phase control. `P,H` uses a separate outer scalar solve,
  the same inner solver policy, and the same explicit phase-mode boundary. A
  future multi-start UI must add capability metadata before exposing that option.

### P0.5 Diagnostics and logging

- [x] Separate three concepts currently easy to conflate:
  - timing collection (`EquilibriumTimingMode`);
  - solver/report detail retained in the result;
  - application logging visibility.
  The default production solve remains quiet and timing-free.

- [x] Add diagnostics policy controls for timing, backend-attempt details,
  conservation/acceptance details, phase-transition reports, and independent
  equilibrium-constant validation when applicable.

- [x] Keep equilibrium-constant validation off or “when applicable” by default.
  The GUI default is `WhenApplicable`; it is an independent validator for
  suitable systems, not a mandatory production gate for arbitrary multiphase
  problems. The default is covered by a model contract test.

- [x] Never change process-global logger configuration from an equilibrium
  document. GUI “logging” means retaining and displaying this run's typed
  diagnostic events; the document and request builder contain no logger
  initialization or global logger mutation.

### P0.6 Pure validation and conversion

- [x] Implement pure, field-addressable validation returning
  `EquilibriumGuiValidationReport`, with errors and non-blocking warnings.
  Validation must not open databases, mutate libraries, start threads, or
  construct solver state.

- [x] Implement one request builder that consumes only a validated config and
  either:
  - builds `PhaseEquilibriumPipelineRequest` for a single point;
  - resolves once and builds `TemperatureRangeRequest` for a range;
  - builds a deferred P,H request which resolves one immutable system and
    `ResolvedThermochemistry` bundle inside the worker.
  No view code may assemble engine requests directly. The first implementation
  lives in `equilibrium_gui_request.rs`; repository resolution and candidate
  discovery remain execution-layer work.

- [x] Add initial unit tests for enum transitions and invalid combinations,
  including P,H bracket/seed validation, duplicate components, zero inventory,
  stale element previews, descending grids, phase-control options, and
  single-backend selection. The remaining request-builder-specific cases stay
  pending with the production conversion boundary.

- [x] Implement the first production request boundary in
  `equilibrium_gui_request.rs`: map validated phases and sparse initial moles
  to the PT pipeline or P,H request, map point/range temperatures to the
  canonical condition/grid types, and map GUI solver/phase/diagnostic policies
  to engine policies. Repository resolution and actual candidate discovery are
  intentionally still execution-layer work.

## P1: execution lifecycle and editor

### P1.1 Background execution

- [x] Define a background-worker-facing lifecycle gate for candidate preview,
  repository resolution, point solve, and range solve. Long solves must not
  block egui. Cancel requests cooperative engine cancellation and the worker
  remains owned until its terminal event is drained. `EquilibriumApp` moves a
  canonical point/range request to a background thread and drains progress plus
  one terminal event on the egui thread.

- [x] Tag every worker message with a monotonically increasing run ID and an
  input fingerprint. Discard stale previews/results after any owning input
  changes, following the reactor IVP lifecycle contract.

- [x] Model lifecycle explicitly:
  `Idle -> Resolving -> Solving -> Cancelling -> Completed/Failed`.
  Range execution also reports accepted point count and current temperature
  when the engine exposes progress. Closing the window must not publish an
  orphaned result into a later document.

- [x] Publish results transactionally. A failed point or range leaves the last
  accepted result clearly marked as belonging to the previous fingerprint; it
  never mixes new inputs with old output. The app also rejects late worker
  messages after an editor fingerprint change, and result snapshots validate
  homogeneous phase/component layouts before publication.

### P1.2 Editor workflow

- [x] Build one work-focused editor with stable sections: Problem, Components,
  Lookup, Phase policy, Solver, Diagnostics, Run status, Results. Avoid a
  marketing/landing screen and avoid nested cards. Result panels remain pending
  until immutable solve snapshots are connected.

- [x] Use segmented controls for mutually exclusive modes, checkboxes/toggles
  for binary diagnostics, numeric fields for physical values, and menus for
  solver/library policies. Advanced controls remain collapsed until selected.

- [x] Provide add/remove/reorder controls for phases, components, elements, and
  custom solver cascades. All four editors are present and invalidate prepared
  requests. Phase, component, and element rows use semantic egui scopes with a
  deterministic fallback while a row is incomplete, so reorder does not bind
  text-editor state to the vector index. The phase identity behavior is covered
  by egui-kittest; persisted row IDs are intentionally not duplicated in the
  document schema because phase IDs and catalog keys already provide the
  canonical identity.

- [x] Show candidate-preview rows as an auditable table with inclusion state,
  exact record key, phase/state, library, temperature support, and rejection
  reason. Selection and phase assignment are visually explicit; manual
  inclusion overrides beyond the engine's selected/rejected decision remain a
  separate policy question.

- [x] Keep accepted results read-only. Show point composition or range summary,
  phase statuses/transitions, residual and balance contracts, selected backend,
  fallback attempts, lookup provenance, timing, and validation status. The
  first read-only result table now shows phase-qualified component values,
  phase status, solver-attempt count, and range reuse evidence; the result view
  now also exposes first-class read-only sections for conservation, residuals,
  fallback attempts, K_eq validation, phase/acceptance evidence, and per-
  component lookup provenance. The sections read the immutable engine report;
  the GUI does not recompute acceptance metrics.

### P1.3 Main GUI integration

- [x] Register the equilibrium modules in `src/gui.rs`.

- [x] Add an independently owned `EquilibriumApp` window to `MainApp`; opening,
  closing, and reopening must preserve the current document without sharing
  mutable state with thermochemistry or reactor windows. The menu ownership
  helper, native child-window kittest, and persistence regression test now
  exercise this boundary.

- [x] Add a clearly named main-menu action. Ownership/lifecycle interaction
  tests for the `MainApp` menu owner and native child-window rendering are
  covered.

## P2: result postprocessing and both plot systems

- [x] Define one `EquilibriumPlotSeries` domain model containing temperatures,
  phase-qualified labels, units, moles, mole fractions, phase totals, and
  active/inactive masks. The role is provided by the immutable
  `EquilibriumGuiResultSnapshot` plus the shared `EquilibriumGuiPlotData`
  projection: basis-specific units and lifecycle masks are aligned with every
  column, and both plot backends consume the same metadata-bearing adapter.
  The public type name remains GUI-specific until a cross-application plotting
  domain is actually needed.

- [x] Add an initial adapter from `EquilibriumGuiPlotData` to the existing
  embedded `gui_plot::PlotWindow`/`egui_plot` path. PNG/export wiring remains
  part of the display-policy pass and does not run another solve. The editor
  now exposes an explicit Open embedded plot action for an accepted snapshot.

- [x] Add an initial KiThePlot `kithe_plot::DataSource` adapter for
  `EquilibriumGuiPlotData` without depending on experimental-kinetics
  `SampledColumns` or `PlotModel`; general display-policy integration remains.

- [x] Let the user choose embedded plot, KiThePlot, both, or neither. This is a
  display policy and must not trigger another solve; both actions now consume
  the same accepted immutable plot adapter.

- [x] Support result basis selection: component moles, component mole
  fractions, and phase totals. Use phase-qualified legend labels and preserve
  exact solver-grid values alongside optional resampled display series.

- [x] Add filtering for visible components/phases and optional logarithmic
  display handling that never rewrites stored zeros or accepted physical
  values.
  Progress: component/phase series can now be hidden through transient GUI
  display state and the common adapter rejects an empty visible selection.
  Stored results are not rewritten. Lifecycle masks are preserved through
  filtering and display resampling; `log10` is a shared display projection
  with explicit positive-value validation, so accepted zeros are never faked.

- [x] Verify point-result table behavior separately from range plots. A
  one-point solve remains one exact point in the shared plot adapter and is
  never sent through PCHIP resampling.

## P3: persistence, hardening, and deferred features

- [x] Add versioned save/load roundtrip tests for `EquilibriumGuiDocument`.
  Solver results, repository instances, workers, and open plot windows are not
  serialized; `EquilibriumApp::load_document_json` starts in a clean idle
  state and drops accepted results, workers, prepared requests, and plots.

- [x] Add `egui_kittest` coverage for:
  direct-species versus element modes; simple gas versus multiphase editing;
  default versus explicit libraries; point versus ascending/descending range;
  production default versus every concrete backend; diagnostics toggles;
  P,H controls and energy-report visibility; phase-control capability constraints; visible validation
  errors; candidate preview and invalidation.
  Progress: element mode, P,H controls, phase hysteresis controls, visible
  validation errors, candidate invalidation, custom cascade editing, and all
  nine concrete backend request preparations are covered. Range direction and
  display-resampling controls, explicit lookup policy, and diagnostics
  sections are now exercised too; postprocessing is kept
  outside the solver fingerprint. MainApp ownership and native child-window
  rendering are covered; OS-level native window behavior remains outside
  this egui test boundary.

- [x] Add lifecycle tests for cancellation, stale preview/result discard,
  success followed by editor changes, close/reopen, failed fallback cascades,
  and transactional range failure.
  Progress: cancellation, stale publication, previous-result retention after a
  current failure, document load reset, and close/reopen ownership are covered
  by direct lifecycle and egui tests. A real repository-backed range failure
  now verifies visible failure, no partial snapshot publication, and catalog
  immutability; real H2/O2/H2O P,H stories now verify inner fallback,
  all-backends-failed publication, cancellation, and rendered backend-attempt
  diagnostics. The complete ignored `equilibrium_gui_tests` story set passed
  in the release profile with serialized execution.

- [x] Complete the real-worker diagnostic matrix with a deterministic
  accepted-candidate validation-mismatch story. The true engine
  `AllBackendsFailed` story and P,H inner-fallback story are covered by the
  ignored local-catalog suite; the regular suite covers the UI and lifecycle
  contracts. The new ignored result-layer story mutates only a test copy of a
  real accepted candidate's validation payload and verifies that the GUI
  rejects it transactionally. Repository-backed stories remain explicitly
  ignored and require the local thermochemical catalogs.

- [x] Add offline story tests using stable local thermochemical fixtures for:
  ideal-gas `P,T`; a real multiphase system; element-defined candidate preview;
  same molecule in two phases; temperature continuation with and without phase
  transitions; provenance, conservation, timing, and backend-attempt display.
  Snapshot the relevant library files before/after tests and assert that GUI
  workflows never mutate them. Progress: ignored local-catalog `H2O` point,
  gas/ice multiphase point, water temperature-range, and exact H/O
  element-candidate preview stories now run through the GUI worker or the
  repository-backed preview path. The candidate story renders the assignment
  audit and snapshots the canonical substance, key, and element-index files
  before and after the workflow; it also assigns one live candidate and
  prepares the canonical request through the solver boundary. The point/range
  stories verify immutable
  provenance, phase-qualified layout, backend-attempt evidence, continuation
  reuse, and non-zero point timing. Both transition and no-transition
  continuation stories are covered, and a separate out-of-coverage range story
  verifies transactional failure without partial result publication.
  The range fixture stays at 250--270 K because the bundled `NASA_cond`
  `H2O(s)` record ends at 273.15 K; the GUI transition story stays inside
  that phase-specific coefficient coverage. The element-defined
  candidate preview now uses the live local catalog and verifies file
  immutability; the GUI water range also asserts a real phase-control
  transition. A separate no-transition continuation story remains useful.

- [x] Add plot-adapter tests asserting identical labels, x grids, values, and
  units for embedded and KiThePlot paths, plus empty/single-point/filtered data
  behavior. Embedded/KiThePlot parity, single-point PCHIP rejection,
  filtered-column behavior, unit metadata, mask preservation, and the shared
  positive-only `log10` display projection are covered. Physical zeros remain
  in the accepted snapshot and are rejected explicitly by the log projection;
  they are not rewritten to a fake finite value.

- [x] Connect `P,H = const` only after the engine-level typed workflow exists.
  The GUI uses total joules, explicit temperature bounds, worker-side
  thermochemistry resolution, and an immutable result energy contract. The
  accepted snapshot also retains the outer route, trial/iteration counts,
  fallback reason, phase transitions, formulation reuse, acceptance limit,
  and optional wall-time evidence; Results renders these diagnostics and the
  complete outer temperature-trial table in a dedicated P,H section. The
  editor fingerprint invalidates a prepared P,H
  request after target, bound, seed, or pressure changes. The
  ignored local-catalog story
  `offline_local_h2o_ph_story_publishes_energy_contract` is the real-data gate.

- [ ] Defer generic export/import formats until the point/range result schema
  stabilizes. When implemented, export immutable typed snapshots rather than
  screen text or mutable solver objects.

## First implementation sequence

1. Create the typed document/config enums and pure validation tests.
2. Implement the production request builder and engine-boundary unit tests.
3. Add worker lifecycle with injected executor fakes and stale-result tests.
4. Build the explicit-species point editor and result diagnostics.
5. Add element candidate preview and phase assignment.
6. Add typed temperature ranges and continuation reports.
7. Add the shared plot-series model and both plotting adapters.
8. Integrate `EquilibriumApp` into `MainApp`, then complete offline story and
   `egui_kittest` matrices.