# Corrections

Versions follow semantic versioning (MAJOR.MINOR.PATCH): a new feature or a change of behaviour raises MINOR, a correction raises PATCH, and a change that older projects or files cannot follow raises MAJOR.

## 2.49.3 - 7 November 2026

1. **One lattice search.** `crystal.js` now holds the only minimum-image search, behind `fracDistance` and the new `fracImages`. Fourier peak-to-atom matching, cell conversion, ADDSYM preparation and the Wyckoff search use it in place of their fixed shells or plain rounding, so they agree on skewed cells.
2. **Contact report.** Neighbours are every image within the cutoff, not those of the 27 nearest cells. A short axis or a skewed cell now lists contacts that were missing, so its coordination numbers and bond-valence sums can rise.
3. **Validation.** Add regressions for all images within a cutoff against an exhaustive search, the contact report in short-axis and skewed cells, and the shared search in each helper. All 265 Node tests pass.

## 2.49.2 - 7 November 2026

1. **Minimum-image distances.** Replace the fixed translation shell with a metric-bounded lattice search so highly skewed, non-reduced cells retain their closest atomic images. The search has a fixed budget, so an almost singular cell returns the closest image found instead of freezing the page. A metric that describes no real cell keeps the rounded image, so its distances stay finite and site symmetry keeps the identity.
2. **Doublet size broadening.** Prepare the secondary line with its own wavelength, preserving the primary parameters and integrated source ratio, in the CPU model and in WebGPU parallel tempering. This changes the calculated pattern of a Kα1/Kα2 dataset with a refined size: refit older projects, because their saved sizes and History records are not comparable until then.
3. **Validation.** Add regressions for the skew-cell example in every axis order, translated and inverted separations, 60 exhaustive oblique-cell comparisons, a strongly skewed non-reduced cell, metrics with no real cell, the bounded search, both doublet size widths, and GPU against CPU cost for a doublet size width. All 262 Node tests pass.

## 2.49.1 - 28 October 2026

1. **Fourier observations.** Keep independent extracted reflections separate instead of merging their `group=-1` markers into one overlap group. Observed, difference and 2Fo−Fc maps now respond to their measured intensity ratios. Refuse Fourier calculation with enabled anomalous corrections, which the map engine does not support, and explain how to select an uncorrected model.
2. **GSAS file exchange.** Import every supported constant-wavelength BANK as a separate dataset. Preserve STD counter-dependent uncertainties (variance I/n), and retain the numerical precision of XYE observations and positive standard uncertainties during GSAS-II export.
3. **Cell safety.** Validate the translation lattice and atomic repetition before contracting a cell, and reject conversions that do not preserve each species' cell content. Conversion cannot apply a plan with violations. Reject nonphysical triclinic metrics during phase creation, CIF import and refinement; volume and basis helpers no longer manufacture a positive volume from a negative metric determinant.
4. **Global restraint statistics.** Count shared copies of each geometric restraint once in the degrees of freedom, including geometry shared through parameter links. Local geometries remain separate, and an unrelated local atom does not duplicate a shared restraint. The restraint objective and weighting are unchanged. Refit restrained global results before using updated reduced chi-square or uncertainties.
5. **Validation.** Add numerical regressions for Fourier intensity sensitivity, multi-bank GSAS import and weights, small-value export, invalid cells, safe contractions, and shared/local/linked restraint counts. Browser Fourier checks also verify the anomalous-correction guard.

No surface roughness, absorption intensity correction, anisotropic atomic displacement or TOF feature was added. The audit's lower-priority secondary-wavelength size-width approximation and extreme-skew minimum-image search remain outside this correction.

## 2.49.0 - 27 October 2026

1. **Phase plot control.** Hide the Phases checkbox when the project has fewer than two phases. Restore it when another phase is added, preserving its saved setting.

## 2.48.1 - 27 October 2026

1. **Project isolation and phase identities.** Clear Fourier results when replacing a project and restore the bundled absorption table when the new project has no custom table. Allocate unused phase keys, enforce uniqueness when adding phases, and reject ambiguous duplicate phase keys before opening a project.
2. **Asynchronous imports and workers.** Prevent pending imports from changing a project during a calculation or after the working project changes. Handle fit-worker startup failures immediately and retain CPU fitting when the optional GPU module is unavailable.
3. **List refreshes and release validation.** Keep dataset searches applied after list refreshes and preserve keyboard focus when phase controls are rebuilt. Correct global-fit tick-source messaging, update the project-symmetry tooltip assertion, and include that suite in browser CI. Add regression coverage for the RC findings.

## 2.48.0 - 27 October 2026

1. **Compact editor descriptions.** Move phase starting-model guidance and dataset observation/instrument details into title help tooltips, visible only for open accordions. Remove the redundant Phase heading. Align phase and dataset leading spacing and use consistent 13 px subsection headings at weight 600. Bold the refinement-group heading, move its guidance into title help, and remove the two separators above it. Remove the repeated Values of heading. Show navigation arrows and a labelled green/red indicator for the inspected dataset in the main Datasets title only while its selection accordion is closed. Shorten the empty-plot message and constrain it to the plotting frame.

2. **Phases list.** Use native list items and inspection buttons, with name and colour in the row Edit dialog. Remove the duplicate Phase name, colour picker and Edit controls from the shared-model editor. Phase editing remains undoable.

3. **Dataset list.** Use native list items with independent inclusion checkboxes, inspection name buttons and Edit/Remove actions. Inspecting an unchecked dataset preserves fitting membership. Mark the inspected dataset separately, retain range selection and keyboard shortcuts, and skip filtered-out rows during arrow navigation. Dataset inspection remains available while fitting.

## 2.47.2 - 27 October 2026

1. **Report precision and project loading.** Preserve very small uncertainties using scientific notation. Validate WPPF precision entry sizes and account for their decoded allocations before reading binary columns.
2. **Refinement controls.** Include phases held only by later selected datasets in global-fit summaries. Make limit and sharing edits and resets undoable; clear stale sharing controls without datasets. Avoid duplicate weight invalidation.
3. **Startup and help.** Allow startup without JSZip, with compression features reporting their existing unavailable-library errors. Make dataset-selection help independent of panel position. Dataset list behavior is unchanged.

## 2.47.1 - 26 October 2026

1. **Third-party licensing.** Add an explicit scope notice to LICENCE: original Powder 6 material uses CC BY-NC-ND 4.0, while bundled third-party components retain their own terms. Identify @spglib/moyo-wasm 0.21.0, its MIT licence option, copyright and retained permission notice. Preserve the Creative Commons legal text and the upstream MIT file unchanged. Add the same scope and links to README and the documentation.

## 2.47.0 - 26 October 2026

1. **Compact results.** Rename Datasets' Sample geometry to Geometry; Sample continues to select size and strain. Remove duplicate result headings, the main Save CIF and Save reflections actions, and Le Bail/WPPF atom sections. Keep Save CIF in the Rietveld 3D structure and rename Save calculated patterns to Save Patterns. Retained atoms still accompany pdCIF exports.
2. **Structure navigation.** Use four sticky tabs styled like Method. Remove the redundant Show structure actions from charge flipping and Wyckoff output; the structures are already displayed below their sites.
3. **Readable exports.** Organise Save results into fit summaries, geometry, background, parameter states, phases and complete reflection tables. Distinguish refined, fixed, linked, constrained and unused parameters, keeping standard uncertainties separate. Store the actual fitted variable names with new results so later checkbox changes cannot rewrite their refinement status.
4. **Zero convention.** State explicitly in text reports and pdCIF comments that zero is observed minus calculated (exp - calc), in degrees 2theta; positive zero moves calculated peaks to higher measured angles. The pdCIF calibration offset remains -zero (calc - exp), added to measured angles. Existing import/export signs are unchanged.
5. **Checks.** Cover both zero signs on pdCIF round-trip, retained atoms, refinement status after flag changes and project reload, full reflection tables in all methods, compact export controls, sticky Structure tabs and saved-result inspection.

Validation: 222 Node tests and 93 checks across six browser pages passed. Changed JavaScript passed syntax checks; the application and documentation changes passed whitespace checks.

## 2.46.1 - 26 October 2026

1. **Background documentation.** State explicitly that 0 Chebyshev terms disables the background, while 1 term gives a constant background (degree 0). Point-based polynomial fitting requires at least 1 term. Clarify the background section, Settings reference and README, and correct the remaining plot-control description to include Chebyshev point targets.

## 2.46.0 - 26 October 2026

1. **Chebyshev background points.** Keep Anchors visible for both backgrounds and show automatically estimated Chebyshev targets. Add, move or remove them on the plot or edit X/Y and Use in Datasets. Point count is independent of polynomial order; degree N requires at least N+1 selected points.
2. **Fit and hold.** Fit to points uses orthogonal QR least squares, rejects underdetermined or poorly distributed points, and holds coefficients during Sample fitting. Editing points refits and holds them; tick Background to restore whole-pattern coefficient refinement. Points in excluded or out-of-range regions are ignored. Spline height refinement is unchanged.
3. **Persistence and scope.** Keep points and selection flags per dataset and per fitting method, with projects, Undo, History and reports. Opening older projects estimates editable point targets without changing their saved background curves. Automatic targets require review; the selected background is a modelling assumption, and holding it makes refinement uncertainties conditional on it.
4. **Validation.** Numerical regressions cover overdetermined signed polynomials, rank and point-count errors, exclusions, fixed backgrounds in all three methods, project archives, Undo and method banks. Browser interaction checks cover Chebyshev placement, editing, selection and two-coordinate dragging alongside the existing spline controls.


## 2.45.1 — 26 October 2026

1. **Linked global refinement.** Include derivatives and parameter counts in every affected dataset, including cross-dataset targets with different names. Preserve the full fitted scope, sharing and limits when preparing global WPPF errors and precision; reuse the joint extraction across sources.
2. **Intensity covariance and identity.** Hold integrated intensity in profile derivatives, including the area derivative and height/profile covariance. Retain all global nuisance directions in precision blocks. Match saved errors and covariance pairs by HKL. Conditional, bound, overlap and legacy errors are identified in reports. Site-symmetry dependent coordinates receive propagated correlated uncertainties.
3. **Profile geometry.** Refresh reflections for each trial geometry, covering both wavelengths and the full permitted tail window. Apply sample corrections separately to each doublet line and normalize secondary heights by area and the Lorentz-polarisation ratio. Measure actual profile FWHM independently of the preserved truncation heuristic.
4. **Physical boundaries.** Diagnose and guard combined Stephens strain variance, including modelled and additional probed reciprocal directions. Start two free zero uniaxial strain components together at up to 1 ppm, with a diagnostic. Active faces, feasible projections and feasible-gradient checks allow other parameters to improve at a variance limit. GPU proposals and retained candidates respect the physical region; metadata names the retained best cost.
5. **Numerical stability and work.** Reuse prepared profile areas and skip unused isotropic reciprocal vectors. Equilibrate WPPF columns; if modified Cholesky becomes unstable on dependent tail columns, use a small relative regularizer and mark conditional errors. Compact GPU active-set factorization to passive intensity columns. A one-iteration Le Bail budget now runs one stage; its Settings tooltip states the total budget.
6. **Checks and compatibility.** Add independent linked-background optima, full covariance/precision references, joint extraction, strain, reflection identity, doublet, FWHM, boundary, GPU rejection, coordinate-export and preparation-count regressions. Repair the WebGPU fixture lookup to use sg/all.json. Existing projects remain readable; refit older calculations before comparing fits or using their intensity uncertainties, because corrected doublets and newly included tails can change fitted values.

Validation: 215 Node tests and 12 browser pages passed, including the complete WebGPU PT suite and a live GPU physical-variance guard check. All application JavaScript passed syntax checks; git diff --check passed.

## 2.45.0 — 26 October 2026

1. **Ctrl+click respects the chosen background.** The anchor-placement handler returns without changing anything in Chebyshev mode. It no longer changes the model to a spline, edits a parameter, enables display options or creates an undo entry. The Anchors checkbox is hidden for Chebyshev backgrounds; spline editing and Ctrl+Shift exclusions continue to work.
2. **One background type for the project.** Background… explicitly selects Chebyshev or Spline for every dataset, including unselected datasets and new patterns. The project setting is authoritative; no dataset acts as a master and reordering the list does not change the choice. Each dataset retains its own term count, coefficients, anchor positions, heights and refinement flags. The explicit bkg>>n and anchors>>n commands select the corresponding common type.
3. **Persistence and History.** The shared choice is stored in the project settings and undo snapshots. Switching fitting methods keeps the common type while restoring each method's own values. History inspection preserves the working setup; Set restores the recorded type across the project.
4. **Checks.** Numerical regressions cover the Chebyshev no-op, unselected and imported datasets, ordering, independent background values, method switching, explicit commands, save/load, Undo and History. The browser check exercises real Ctrl+click input, the hidden Anchors control and explicit spline selection in Background….

## 2.44.0 — 26 October 2026

1. **Parameters before Links.** Rename Parameter links and sharing to Parameters, directly before Links at the same level. Bounds remain available for the dataset being inspected.
2. **Show sharing only where it applies.** The Shared column, checkboxes, padlocks and Sharing button appear only for global fits with multiple selected datasets that hold the independent parameter. Local background/scale values, linked dependent parameters, unselected datasets and parameters held by only one selected dataset do not offer a sharing checkbox. Switching fit mode or selection preserves the sharing preferences. Reset limits does not reset hidden shared flags.
3. **Hide an empty Links block.** Parameters offers Add parameter link… until a relationship exists. Creating the first link reveals Links, including for a link within one dataset; removing the last hides it again. Existing relationships remain manageable in individual fits.
4. **Checks.** A browser regression exercises single and global fits, parameter applicability, within-dataset link creation, dependent targets, selection changes, reset behavior and removal of the last link. Workspace, responsive UI and restraints-helper browser checks cover the new section order and compatibility.

## 2.43.1 — 26 October 2026

1. **Remove the horizontal scrollbar below Structure.** Dataset parameter rows and background/exclusion headers inherited negative side margins intended for a padded container. In the dataset editor the container has no padding, so the rows extended four pixels outside it and created a horizontal scrollbar below the whole parameter list, including Structure. The dataset rows now keep their margins inside the container.

## 2.43.0 — 26 October 2026

1. **Real density in charge flipping.** Initial phases of centric reflections obey their phase restrictions, including translated inversion centres. Weak Friedel partners receive opposite quarter-turns on the CPU and GPU, independently of whether a symmetry operator generated each member directly. This prevents their density being lost into an imaginary component. The worker requires the updated shader marker to reject a cached older kernel.
2. **Keep independent sites in high symmetry.** The peak limit applies after symmetry reduction, rather than truncating the full-cell peak list before equivalent images are merged. A cubic regression map with three independent 48-fold sites retains all three.
3. **Refuse stale intensities.** Parameter edits clear the current extraction when it no longer matches the cache. Both charge-flipping and Wyckoff launch handlers independently check freshness, including dataset values and the fit record; disabling a button is not the only guard.
4. **Name peaks by integrated charge.** CF sites retain their integrated charge and normalized charge through results, History and projects. Formula assignment and automatic Z use the largest integrated charge; older results without integrals keep the height fallback. The sites table shows both Height and Charge. Element assignment remains a chemical heuristic.
5. **Atoms and Structure.** Each phase's atoms are grouped in a collapsible accordion in Phases and in the dataset's Rietveld controls. A separate Structure accordion immediately follows the atom list, so collapsing the atoms leaves the viewer accessible. Dataset structures use that dataset's constrained coordinates, cell, occupancies and displacement parameters. The Phases Structure heading remains available even before atoms are added.
6. **Regression coverage.** Numerical checks cover centric amplitudes, translated inversion, real density in all 230 standard space-group settings, weak-reflection survival and full symmetry orbits. Browser checks cover the real CPU/GPU weak-reflection paths, stale launch rejection, charge-based element assignment and independently collapsing atoms beside a working Structure viewer.

## 2.42.17 — 26 October 2026

1. **Save CIF only for a phase that has atoms.** The per-phase button of 2.42.16 appeared on every phase group, including one whose cell and space group carry no sites: that CIF says "Atomless phase: no atomic coordinates have been invented", which is a file nobody asked for. The button now appears only when the phase has atoms, and `savePhaseCif()` refuses an atomless phase with a message if it is called anyway. The `ui-consistency` browser check asserts both states — no button, then one atom, then one button whose CIF carries that atom.

## 2.42.16 — 26 October 2026

1. **A separated profile was not checked at all.** The variance guard and its diagnostic (2.42.14, 2.42.15) read `inst.GU, inst.GV, inst.GW` for every non-split resolution type, but a separated profile is the instrument's `U, V, W` whatever its type (`profileParams` writes `inst.U …` from `instrumentProfileParams`). For a dataset whose `resolutionType` is `gsas_cw` — older projects, and the fixture the `ui-interactions` browser check uses — the lookup found nothing, fell back to zero and reported a variance of zero: no warning, and no boundary for the refinement. The names now follow the owner: `U, V, W` for the instrument and for a TCH phase, `GU, GV, GW` (with GP folded in) for a phase-owned pseudo-Voigt, `U_L…`/`GU_L…` for the two split flanks. A Node test walks all four resolution types; the browser check is what caught it.
2. **Question marks only in open blocks.** A block title's help icon explains what the block opens, so it is hidden while the block is closed — `details:not([open]) > summary .acc-help`, which covers both the `acc` and the `object-group` accordions.
3. **No duplicate phase actions over the 3D picture.** The 3D structure block of charge flipping and of the Wyckoff search repeated **Atoms to the phase…** and **Save CIF…** in its header, one line under the same two buttons beside its sites table. The header keeps the label and the site count; the actions stay with the list.
4. **Compute the map says why it cannot.** The Fourier button is disabled, with the reason in its tooltip, until the phase has atoms and its WPPF intensities exist for the chosen dataset. It follows the phase chips, the dataset selector and every fit or atom edit, and `run()` reports exactly the same reason when it is called anyway.
5. **Save CIF for one phase in Datasets.** Every phase's parameter group carries **Save CIF…**, which writes that phase alone (`structure_<phase>_<stamp>.cif`) from the values of the dataset being edited, with the standard uncertainties of the last Rietveld fit. Results → Save CIF still writes every selected phase.
6. **Tests.** A Node regression test for the resolution-type names (190 Node tests pass), and three browser checks: the question mark appears with its block and a phase CIF is written from Datasets (`ui-consistency`), the disabled and enabled states of Compute the map (`fourier`), and no buttons in the 3D structure header (`cf-transfer`).

## 2.42.15 — 26 October 2026

1. **A non-negative Gaussian variance is now part of the model, not a warning.** 2.42.14 fixed the start values and reported the invalid region, but a fit could still walk into it: the width floor turns a negative variance into "no Gaussian component", the pattern barely changes there, and the coefficients slide along a flat valley into numbers that mean nothing (a synthetic fit reached −302 cdeg² at 145° with no complaint). A Levenberg–Marquardt step that would make any Gaussian variance negative over its fitted range is now **cut back to the boundary**: the step fraction is bisected (24 iterations) while the variance stays non-negative, so the coefficients stop at the limit and the fit can still run along it. The rule covers every polynomial `instrumentProfileWarnings()` reports — the dataset's `inst.U/V/W` for a separated profile, and a phase's own `pN.U/V/W`, `pN.GU/GV/GW` (GP folded in) and both split flanks — through one builder (`gaussianVarianceGuards()`) that both the guard and the diagnostic use, so they cannot disagree about what is checked.
2. **The same rule applies to parallel tempering and to the WebGPU finish.** A replica inside the region may not accept a proposal outside it (one that is outside is left free to come back), and a WebGPU PT result outside the region is not taken: the double-precision LM finish starts from the point that was inside.
3. **A fit that starts outside the region is not walled in.** An old project, or values typed in by hand, may begin with a negative variance — it can still come back, and the diagnostic still reports it. A fit that *ends* on the boundary adds a warning naming the polynomial, the 2θ where the variance reaches zero and the fact that the Gaussian width is at the floor, with the usual cause and the usual fix.
4. **Tests.** A regression test generates data from the pre-2.42.14 profile (whose variance is negative in the middle), fits from a valid start and asserts that both the LM path and the CPU PT path end with a non-negative variance, that the guard actually binds (the minimum is at zero), and that the boundary warning appears. 189 Node tests pass; no measurable cost (13.0 s before and after).

## 2.42.14 — 26 October 2026

1. **The TCH start values described a profile that cannot exist.** `TCH_default.json` (and `PROFILE_PARAMS.tch_aniso` behind it) shipped U = 17.4, V = −45.2, W = 16.5 cdeg², whose Gaussian variance `U tan²θ + V tanθ + W` is **negative from 47.4° to 130.3° 2θ**, with a minimum of −12.854 cdeg² at 104.8°. Every TCH refinement therefore started with no Gaussian component over most of the pattern: the width floor turns a negative variance into the minimum resolvable FWHM, so the peaks there are pure Lorentzians, U, V and W have no effect on χ², and the fit drifts through the flat valley that leaves behind. A synthetic TCH fit started from a valid set (2, −2, 5) ended at U = −42.9, V = +41.7, W = −3.0 — a variance of −302 cdeg² at 145° — and nothing said so. The start values are now U, V, W = 2, −2, 5 (the Gaussian polynomial of the Voigt and Split presets), X = 1 (= LX), Y = 0, and SL = HL = 0: axial asymmetry belongs to the instrument calibration, and 0.1/−0.25 gave an asymmetry coefficient of 0.89 at 10° 2θ, which squashes one flank to about a tenth of its width. The preset also carried X and Y the other way round from the built-in list.
2. **The negative-variance diagnostic now covers phase-owned coefficients.** It looked only at a dataset's `inst.U, inst.V, inst.W` for a separated (GSAS) phase, so a `tch_aniso` phase refining its own U, V, W was never checked — exactly the case in (1). `gaussianVarianceMinimum()` finds the minimum of the quadratic over the fitted range (both ends plus the interior vertex when U > 0) and `instrumentProfileWarnings()` applies it to the instrument polynomial of a separated phase and to `pN.U/V/W`, `pN.GU/GV/GW` (with `GP` folded in as `GP/cos²θ = GP + GP tan²θ`) and the two split flanks. The message names the parameters as the panel shows them (`p1.U, p1.V, p1.W`). It is still a diagnostic: nothing is reset.
3. **Tests.** Two regression tests: the start values of all three presets and of `PROFILE_PARAMS` have a non-negative variance over the whole angular range, and the preset agrees with the built-in list; and a phase-owned TCH polynomial holding the old values is reported while the new ones are not. 188 Node tests pass.

## 2.42.13 — 26 October 2026

1. **The absorption-table rules are a module of their own, and tested.** `js/rietveld/rv_absorption.js` carried parsing, validation and interpolation inline, where no test could reach them. They are `js/absorption_table.js` now (no DOM, no state): units, element keys, ordering, the post-edge row at a duplicated energy, log-log interpolation and the refusal to interpolate across a sharp edge. `tests/absorption.test.cjs` pins each of them, including two things the old code did in silence: `Fe`, `fe` and `FE` are one element (a document holding two spellings is an error, not a coin toss), and the messages now name the energies or the unit instead of saying "invalid".
2. **The estimates cannot produce NaN any more.** `sample()` looks the Rietveld mass fractions up by phase key rather than by array position, and checks that every phase density and the mixture density are finite; `predict()` checks `µ90` before dividing by it; `phaseComposition()` names a site without a multiplicity instead of multiplying by `undefined`.
3. **The CIF path no longer invents a cell.** A structure CIF missing a cell parameter the crystal system leaves free is refused with the tag names (`_cell_length_b, _cell_angle_alpha, …`); it used to be completed by `normaliseCell` (b = c = a, right angles) without a word. `js/cif_structure.js` reports `cellMissing` and `atomsSkipped`, drops an e.s.d. anywhere in a number (`1.23(4)(5)`, `1.2(3)e-2`), reads bare fractions (`1/2`), and turns `?`/`.` labels and types into `''` so the caller derives the element from the label; `readStructures` says how many sites were skipped.
4. **Tests.** `tests/absorption.test.cjs` (3) and `tests/cif-structure.test.cjs` (4) are new, plus a regression test that a cubic CIF giving only `a` imports while the same file as P1 is refused. 186 Node tests pass; the browser pages `workspace` (bundled `absorption.json`), `phase-atoms`, `project-save` and `convert-files` pass.

## 2.42.12 — 26 October 2026


1. **`sg/` carries only the file the page reads.** It held 230 per-group files and `sg/index.json` (4.69 MB) that nothing fetched: `rv_app.js` loads `sg/all.json` once, and the picker lists every group from it. They were the staged lazy-load layout, so `scripts/cctbx_Harko_v1.py` now writes `sg/all.json` by default, the split layout only with `--split` (it used to be written always) and the old formatted monolith only with `--legacy` (it used to be written unless `--no-legacy`). A re-run no longer recreates 231 unused files.
2. **Unused scripts and reference data removed.** `scripts/cctbx_generate_sg_harker_v7.py` (schema 7; the shipped data is schema 8 and names `cctbx_Harko_v1.py` as its generator), `scripts/wyckoff_patch.py` and `scripts/wyckoff_probe.py` (instructions for patching a `cctbx_generate_sg_harker_v6.py` that does not exist, applied long ago), and `tools/cif_pd.dic` (the powder CIF dictionary, 522 KB, read by no code). `tools/` is gone; `scripts/` holds the two generators that produced the shipped data.
3. **Verified.** `python -m py_compile scripts/cctbx_Harko_v1.py`; 178 Node tests pass; the `workspace` and `wyckoff-search` browser pages pass — the latter runs the real GPU Wyckoff search on the shipped `sg/all.json`.

## 2.42.11 — 26 October 2026


1. **The last references to removed code.** `profile.js`'s `intensityDerivativeColumn()` still documented a flat-list form "from `bucketContributionsByPeak`" (deleted in 2.42.9) and carried the flat-list branch that no caller used — the one caller, `rietveld_core.js`, passes the buckets it builds itself. The function takes `buckets` only now, and its doc says where they come from. `wyckoff_worker.js`'s note on automatic Z no longer cites `suggestZ()` by name; it describes the volume-per-atom estimate it replaced.
2. **Verified.** 178 Node tests and the `wyckoff-search` browser page pass; no numerical behaviour changed.

## 2.42.10 — 26 October 2026


1. **The code layout in the documentation lists every file.** It was missing 14 of them (`pt_gpu.js`, `cf_adaptive.js`, `distance_rules.js`, `wyckoff_limits.js`, `atom_restraints.js`, `molecule_rules.js`, `fourier_map.js`, `rv_fourier.js`, `rv_restraints.js`, `rv_fit_history.js`, `rv_project.js`, `rv_layout.js`, `rv_workspace.js`, `rv_wyhelper.js`); each has one line now, next to the files it works with.
2. **Comments that described code which is gone.** `swarm_wyckoff.js` opened with "Harko.html calls runWyckoffSearch()" and required a `cc_fitness.js` that does not exist (and cited it as the CPU reference for a duplicated ramp formula); both are corrected. `verifyScatteringTable()`'s docstring said a failure "should stop the run", while `rv_app.js` reports it and continues — the docstring now says what happens, and why.
3. **Dead style and dead ids.** `powder6.css` had a `.results-pane` class that no element carries and a `.sv-shared` rule for a class nothing uses; both are gone. `index.html` carried nine ids that no script, stylesheet, test or `aria` reference reads (`calc-tab-lebail/wppf/rietveld`, `sp-phases`, `sp-fit`, `wppf-tools`, `dataset-properties`, `dataset-parameter-host`, `dataset-limits-title`) — the elements are found by their classes and `data-` attributes, so the ids went.
4. **CI runs six browser pages instead of two.** `file-readers`, `pattern-only`, `project-save` and `solve-fixes` join `ui-consistency` and `ui-interactions` in the matrix; all four are GPU-free and were run locally before being added. `.vscode/settings.json` now serves on the documented port 8000 rather than 5501.
5. **Verified.** 178 Node tests pass, and `ui-interactions`, `workspace`, `restraints-helper`, `file-readers`, `pattern-only`, `project-save` and `solve-fixes` pass in headless Chrome.

## 2.42.9 — 26 October 2026

1. **`symmetry_utils.js`: 968 lines to 222.** The Wyckoff worker used two functions from it — `sharkoOrthMatrix()` and `sharkoReducedCell()` — and nothing anywhere (tests included) called the rest: a 3-D FFT, a Patterson synthesis, Gaussian map smearing, space-group setting resolution with `expandReflections`, a fractional-to-Cartesian length and a minimum-image distance. Those sections, the 40-line comment about a `sharkoLorentzPolarization` the file no longer defines, and the `console.warn` that guarded it are gone; the header no longer claims callers that do not exist, and the worker's load-order note no longer makes `crystal.js` a dependency of this file.
2. **`wppf_linear.js`: 816 lines to 507.** A complete second WPPF solver — contribution bucketing, per-peak profile columns, `buildIntensityNormalEquations()`, `solveWppfIntensities()` and `weightedCostFromColumns()` — had no caller and no test; `rietveld_core.js` solves through `intensityEnvelope()` and `solveSkylineNNLS()`. Two implementations of one objective are how the live one drifts without anyone noticing, which is the failure this repository has recorded twice already.
3. **`observations.js`, `contacts.js`, `crystal.js`, `wyckoff_assign.js`, `polarization.js`.** Removed the unused statistical block of `observations.js` (`groupPowderObservations`, `powderResiduals`, the regularized-beta/F-test chain and `hamiltonRatioTest`, 590 → 376 lines, `obsGroupVariance` kept because the search uses it), the structure-quality block of `contacts.js` (`siteQuality`, `structureFactors`, `structureRFactor` and the bond-valence tables they alone used, 602 → 429), `buildInvDsqEvaluator`/`updateHklPositions`/`MONOCLINIC_FIXED_ANGLES_FOR_AXIS` from `crystal.js` (711 → 499), the dead `allocateParticles`/`suggestZ` exports of `wyckoff_assign.js`, and the four unused wrappers of `polarization.js` plus the unread `weak` field of the French-Wilson result.
4. **Two dead files.** `moyo-wasm.tgz` was a byte-identical copy of `lib/moyo/` (an unpacked npm tarball), and `tools/export_ionic_scattering.py` a byte-identical copy of `scripts/export_ionic_scattering.py`. Both deleted; `tools/` now holds only the powder CIF dictionary, which code does not read (kept as reference). The `sg/<n>.json` files stay for now: they are the staged lazy-load layout `cctbx_Harko_v1.py` writes, and switching the page to them is a separate change.
5. **One real no-op loop.** `quench()` in `swarm_wyckoff.js` looped over `coordsPerParticle` values to call `quenchPropose()` only when the index was 0; it now calls it once per particle.
6. **Verified.** 178 Node tests pass, and the browser pages `wyckoff-search` (real GPU search and CPU refinement), `solve-fixes`, `phase-atoms` and `workspace` pass; no numerical behaviour was touched.

## 2.42.8 — 26 October 2026

1. **One erfc, not two.** `polarization.js` and `profile.js` each carried the Numerical-Recipes `erfc` polynomial. The `polarization.js` copy had the negative-argument branch (`erfc(-x) = 2 - erfc(x)`); the `profile.js` copy — used by `asymmetryAreaCorrection()` — did not, and was correct only because every caller passes a positive argument. `profile.js` now defines `sharkoErfc(x)` once (both signs, the digit that matters documented in place), uses it in the asymmetric-area tail, exports it, and `cfErfc()` in `polarization.js` delegates to it. `pt_gpu.js` keeps the f32 WGSL copy, and both comments say so.
2. **A test that would have caught the digit.** `tests/numerics.test.cjs` checks `erfc(0) = 1`, `erfc(1) = 0.157299207050285` and the reflection formula at four arguments.
3. **No numerical change.** The polynomial is the same one the two copies held (they agreed apart from the missing branch); all 178 Node tests and the Solve browser page pass.

## 2.42.7 — 26 October 2026

1. **Shortcuts stay out of open dialogs.** While a modal dialog was open, F9 started a fit behind it and Ctrl+S opened a second save prompt; only the space-group overlay stopped them. Both now return while `#dlg` is open, and F9 no longer fires from inside a text field (Ctrl+Z already did not). `rv_app.js`.
2. **A failed start-up says so.** `loadDatabases().then(...)` had no rejection handler: an exception from a `phases`/`tables` listener left the page half-started with an unhandled rejection and no message. It now says "Start-up did not finish: …" and what to check.
3. **The project.json size limit no longer depends on JSZip's internals.** `declaredSize()` reads JSZip's private `_data.uncompressedSize`; if that ever disappears the check silently becomes a no-op before `JSON.parse`. The decoded string length is now checked as well, and a read failure is reported as such instead of as "not valid JSON" (`rv_project.js`).

## 2.42.6 — 26 October 2026

1. **Distance rules no longer drop a token after the range.** `S O 4 1.40/1.60 2.0` and `S O 4 1.40/1.60 3` were accepted with the last number or count silently discarded — the same defect the 2.42.0 release fixed for the `A B dmin dmax` form, still present in the `A B N dmin/dmax` one. Both now fail with `"2.0" after "4 1.40/1.60" is not read - a rule is "A B dmin dmax" (or "A B N dmin/dmax [shape]")`, so a rule cannot say one thing and enforce another (`distance_rules.js`, one guard; covered by the existing "never drops a token" test).
2. **The scattering loader names a file that exists.** A `scatters/index.json` without `preferred` fell back to `xray_wk1995.json`, which this repository has never contained (the shipped table is `xray_wk1995_ions.json`), so the fallback could only fail. It now names the shipped file.
3. **An ion the f0 table lacks is reported, not hidden.** `makeFormFactor()` silently used the neutral atom's f0 when the requested charge state was absent from the table — a substitution worth a few electrons that looked exactly like a successful lookup. It still uses the neutral factor (a point-atom fallback would be worse) but logs the substitution once per species, and the docstring says so. Covered by a new test in `tests/anomalous.test.cjs`.
4. **Adaptive CF diagnostics no longer spread a whole reflection list over the stack.** `cf_adaptive.js` used `Math.min.apply(null, list)` / `Math.max.apply`, which passes one argument per reflection; on a large extraction that is a `RangeError`. Two tiny loops (`minOf`, `maxOf`) replace them, with the same empty-list result. All 177 Node tests pass (the new one included).

## 2.42.5 — 26 October 2026

1. **The tuning constants now say what the code does.** `constants.js` carried a block of LM, PT, finite-difference and Le Bail switches that nothing read, so changing `PT_NUM_REPLICAS`, `PT_MAX_TEMP`, `LM_TRUST_INITIAL`, `LM_COST_TOL`, `FD_MAX_PROBE_FRACTION` or `WPPF_VARPRO_EXACT_JACOBIAN` had no effect — and several documented values contradicted the code: 8 replicas against 6, `PT_MAX_TEMP` 1.0 (a value the validator rejects) against 100, a 0.05/1.6 trust region against Marquardt's `mu = 1e-3`, `nu = 2`. The values the fit uses are the constants now, and `rietveld_core.js` reads them: `PT_NUM_REPLICAS` (6), `PT_MAX_TEMP` (100), `LM_CONVERGED_REPEATS` (2, replacing the literal `2`) and `FD_BASE_FRACTION` (1e-4, replacing four literal copies in `fdStep`). The switches with no code behind them are gone, with their comments, so the file no longer advertises a ladder, a refresh interval or a trust region that do not exist.
2. **One copy of each default.** `rietveld_core.js` no longer carries guarded copies of the Le Bail and WPPF constants (`constant(name, fallback)`), and `rv_solve.js` no longer carries a second `CF_DEFAULTS`: both read `constants.js`, which every entry point loads first. `CF_DEFAULTS` is exported for the Node suites and its dead `gridSize` is removed. `setMinProfileFwhmFromAxis()` is gone — nothing called it, and the floor that acts in a fit is the dataset's own two median steps (`rv_state.js` `datasetDef.minFwhm`); `medianStep()` now carries the reason it is the median and not the mean, which was the only place that reasoning lived.
3. **Tests.** All 176 Node tests pass; the numbers the fit sees are unchanged (the constants and the literals they replaced agree).

## 2.42.4 — 26 October 2026

1. **History keeps phase restraints and anomalous tables.** Calculation checkpoints now store each phase’s geometric restraints (`rv_fit_history.js`, `phaseDoc`), so exported text and PDF reports include `## Restraints` when inspecting a saved run, **Set** / **Use as start** restores them, and editing restraints marks the working setup as changed since the run. History sections that carry both key–value pairs and a table (`Anomalous scattering`) now render and export the per-element `f′`/`f″` table instead of stopping after the key–value list.
2. **Parameter links and saved calculations follow structural edits.** Parameter links follow renamed atoms, are pruned when a linked phase, atom, dataset-phase assignment or free variable leaves the model (`rv_state.js`, `pruneLinks`), convert their displayed multiplier to display units (`rv_workspace.js`, `rv_panels.js`), and use collision-free IDs. Adding an atom or editing a phase clears stale entries in `ds.mem` and saved calculation banks (`ds.calculations`).
3. **Fourier maps, Wyckoff quench and coordinate refinement.** Parabolic sub-voxel interpolation of negative difference-map peaks (`fourier_map.js`) no longer negates the offset for holes, and nearest-atom / equivalent-peak distances search the 27 lattice translations in oblique cells. The Wyckoff closing `quench()` (`swarm_wyckoff.js`) reuses the full-resolution fitness just computed by `rescoreAtFullResolution` instead of running a duplicate GPU evaluation pass, and mixes single movable-site proposals (75 %) with collective movable-site proposals (25 %), leaving fixed special positions untouched. `refineCoordinatesAgainstWppf` (`coord_refine.js`) reports the actual number of accepted steps.
4. **Style and tests.** Four literal radii and a heading font size in `powder6.css` now use `:root` tokens (`--radius-xs`, `--fs-md`). Node regression tests cover History restraints and anomalous tables, link renaming and pruning, negative Fourier peak interpolation, oblique minimum-image distances and `coord_refine` step counts.

## 2.42.3 — 26 October 2026

1. **A smaller question mark.** The help icon is 80 % of a small control (`--help-q-h`, `--help-q-fs` from `--ctl-h-sm` and `--fs-sm`) everywhere it is used, so a title line carries it without shouting. It is the same widget in every panel, and the help it opens is unchanged.
2. **Datasets: four more titles.** Constraints (its rule help), Restraints (the rule reference and what restraints do) and Links (what a link is: “A dependent parameter follows one independent source exactly. Links can connect different phases or datasets for this method.”) each carried a question mark in, or above, their body; they are in the title now, at the right end, like the Structure blocks. The Restraints description and the Links description are gone from the bodies; the Constraints guidance (“Choose a relationship …, then click Add”) stays, because it says what to do rather than what the section is.
3. **Parameter links and sharing is its own section.** It was an accordion nested inside Links (moved there and renamed at start-up); it is a sibling of Links now, directly below it and above Copy, with its explanation (“A refinement keeps every parameter between its limits …”) in its title icon instead of a paragraph. `index.html` carries the section, `rv_workspace.js` only places it after Links.
4. **Tested.** `tests/restraints-helper.js` checks the four title icons and their help, that the two descriptions left the bodies, that the restraint rule reference is in the title, and the order Constraints → Restraints → Links → Parameter links and sharing → Copy.

## 2.42.2 — 26 October 2026

1. **The explanations of the Structure blocks are in their titles.** WPPF intensities, Space group, Charge flipping and Wyckoff search each began with a paragraph of explanation above the form; all four are now the question mark at the right of the title, like the block-level help introduced in 2.42.1 (`BLOCK_HELP` in `rv_solve.js`, `block()`'s optional help argument). The form starts directly under its title.
2. **Space group.** The title carries one text for both tools — the probability of each set of absences from the WPPF intensities and their correlation (Markvardsen, David, Johnson and Shankland 2001), and finding the symmetry of an atomic model, conversion to the detected group and the Moyo engine. The two sub-blocks keep only what the title does not say: the condition-free group a complete test needs, and which model ADDSYM reads.
3. **Charge flipping.** The paragraph below the formula unit is gone; the title's help states the method (Oszlányi and Sütő 2004, GPU where there is one, CPU otherwise, the peaks put on the origin of the group and reduced to the asymmetric unit) and then what the formula unit and Z are used for, with the density the form currently gives.
4. **Fourier map.** Its question mark was a button at the top of the form; it is the same icon in the title now, so all five blocks of Structure read as one column of titles.
5. **Tested.** `tests/solve-fixes.js` checks each of the five titles for its icon and label, that the paragraphs are gone from the bodies, and that the charge-flipping help still carries the method and formula text.

## 2.42.1 — 26 October 2026

1. **One help icon, in the title.** The Charge flipping form carried a question mark after Z (a "?" whose help was the density hint) beside a second one for the formula help, so the row ended in two marks and the density hint sat under the Z field instead of with the rest. Both are gone from the row: `formulaRow()` renders the formula unit and Z only, and `block()` takes an optional help icon that sits at the right end of the title (`powder6.css`: `.acc > summary .acc-help`, right-justified and centred on the title line). `renderDensity()` keeps that icon's help current — the formula and Z explanation plus the density the form gives now, in the warning colour while the formula cannot be read or the density is impossible — so nothing the removed marks said is lost.
2. **Using it does not toggle the block.** A button inside a `<details><summary>` inherits the summary's default action: the icon now cancels the click (and Enter/Space) so the help can be read with the block open or closed (`js/rietveld/rv_solve.js`, `init`).
3. **Tested.** `tests/solve-fixes.js` checks that the formula row has no question mark, that the icon is the last element of the charge-flipping title with its label and help, that the help follows the typed formula and Z, and that clicking the icon leaves the block as it was.

## 2.42.0 — 26 October 2026

1. **A saved project is no longer "modified".** The preset files beside the page (`Voigt_default.json` and its siblings) were fetched after the space groups and the scattering tables, and their values are part of the saved document: a save made in the first moments of a session compared the project against a document the presets had not reached, so `hasUnsavedChanges()` answered yes with nothing edited and closing the page asked whether to discard changes. The preset load starts first, is one promise for the page (`RV.cmd.defaultPresetsReady()`), and saving and opening a project wait for it. `setPresetDefault` now only fills in a shape the document does not carry, so a project opened before the files arrive keeps its own start values. This was also a browser-test failure that passed or failed by timing (`tests/project-save.html`).
2. **The saved-state check no longer copies the archive.** `RV.project.snapshot()` cloned the whole solution state (`RV.solve.archive(false)`) on every save and on every leave-page check — a second copy of every reflection table and of the WPPF precision block, tens of megabytes with a solved structure. `RV.solve.archiveFingerprint()` mixes the same values into a 32-bit hash without allocating them.
3. **Project format 4: the precision block in its own entry.** The WPPF precision block (a 600×600 matrix in a cimetidine-sized project) was written as text inside `project.json`, and a Wyckoff result carried a second copy of the extraction it was made from. The block is now a little-endian binary entry (`solution/precision.Q.f64` and `solution/precision.index.i32`) and a solution refers to its extraction (`intsRef`), which `restoreArchive` reconnects. Format 3 still opens; both are read by the same code.
4. **Distance rules never drop a token.** `A B 2.0 2.2 2.4` used to be accepted as 2.0–2.2 Å with the third number silently ignored; it is now an error naming the token. `A B 4 1.4 1.6` (a count and two distances) used to be reported as "dmax (1.4) is below dmin (4)"; it now suggests `A B 4 1.4/1.6`. Either the Wyckoff constraints or the Rietveld restraints see the same messages, through `js/distance_rules.js`.
5. **Searches can be repeated from a seed.** The Wyckoff search drew its initial coordinates, its restarts, its replica exchanges and the per-chain seeds of the kernel from `Math.random()`, so a run could not be repeated and two strategies could not be compared on the same starts. One seeded stream (mulberry32) now feeds all of them, from a **Seed** field in the Wyckoff search and in charge flipping: blank draws a new seed, which the Log, the result, History and the project record; a typed seed repeats the run. `js/swarm_wyckoff.js` exposes `swSetSeed`/`swSeed`, the worker seeds each job from it, and History lists the seed of charge flipping and of the Wyckoff search.
6. **Tests and notes.** New Node checks cover the seeded stream and its plumbing, the stricter rules, the preset guard, the version-4 precision block (pack and unpack, including the missing, oversized and format-3 cases). `CLAUDE.md` now names `tests/anomalous.test.cjs` and `tests/wyckoff-adaptation.test.cjs` in the Node command that skipped them, and `CODE_REVIEW.md` records which of its findings are closed.

## 2.41.0 — 25 October 2026

1. **Subgroups….** Structure → Space group → ADDSYM has a Subgroups… button beside Find higher symmetry…. It lists the maximal subgroups of the phase's space group, translationengleiche (the lattice kept, the point group reduced: Fm-3m → I4/mmm, index 3) and klassengleiche (the point group kept, the lattice reduced to a sublattice of index 2, 3 or 4, so the cell grows: Fm-3m → Pm-3m). Each row gives the type, the index, the space group in its standard setting, the new axes and origin, and the new cell. Convert… then opens with that group and transformation: the atoms are kept and the sites the lower symmetry no longer relates are split.
2. **How the list is made.** `js/sg_subgroups.js` works from the operators of the setting, with no table of groups: it takes the maximal subgroups of the point group (t) and the invariant sublattices with a section of the group over them (k), keeps the maximal ones, and has the bundled Moyo engine name each one from two atoms at general positions under its operators. The list of Fm-3m agrees with the International Tables (F432, F-43m, Fm-3 at index 2; I4/mmm at 3; R-3m, Pm-3m and Pn-3m at 4).
3. **A correction in Convert….** A transformation to a larger cell was called "another setting of the same group" when the new group matched the old operators: the old lattice was not compared with the new one. The old group is now taken as inside the new one only when its lattice is.
4. **Clearer Convert… labels.** The Find box, which only shortens the New space group list, is Filter list; the Transformation choice Find it / Enter it is Axes and origin: Work them out / Enter them, with a hint on each, and the dialog introduction points to Subgroups….
5. **Constraints on a phase added under another method.** A phase added while Le Bail or WPPF was active was missing from the saved Rietveld calculation, and setting an atomic constraint on it failed with "No value for constrained parameter …". Calculations that do not hold the phase are skipped; switching to Rietveld takes their values from the phase.

## 2.40.0 — 25 October 2026

1. **Dependent parameters follow their tick.** In Parameters, a parameter that follows another (an equivalence constraint, or a parameter link) stays disabled but now shows the refine tick of the parameter it follows, instead of an unchecked box.
2. **Restraint table lists every restrained value.** The geometry table under the restraint rules showed only values outside their window, so a rule that is satisfied (for example C1–N1 inside 1.00/1.20) seemed to be missing. All restrained values are listed, violations first, with "in window" for the satisfied ones.
3. **Save peaks.** The Fourier Peaks block saves the peak list (sign, x, y, z, σ, height, nearest atom, distance, copies) as CSV.

## 2.39.0 — 25 October 2026

1. **Automatic anomalous scattering.** Copy Hephaestus's 92-element Chantler data file into `scatters/anomalous_chantler.json` and interpolate signed f′ and f″ linearly in photon energy at each dataset's λ1. The Instrument checkbox defaults on for X-rays and is disabled for neutrons. Turning it off removes the corrections from CPU and GPU fit jobs. Table bounds are respected without extrapolation; ionic species use their element's anomalous values.
2. **Values used, recorded.** Text, PDF and History reports include enabled state, source, wavelength, energy, interpolation and per-element corrections. Completed fits store the exact job values, preserved through projects and archived-result inspection even if the current table changes. Legacy explicit values remain readable; applying Instrument returns to the automatic or disabled choice.
3. **A smaller Instrument dialog.** Remove manual anomalous-value entry and Fit from/to fields. Exclusions remain the region editor; existing dataset range limits are preserved. The monochromator tooltip omits reflections that cannot diffract at the entered wavelength.
4. **Validation.** Regression checks cover all 92 copied tables, interpolation and boundaries, enable/disable and neutron behavior, cache invalidation, report provenance, and saved-run/project fidelity. Browser checks cover the checkbox, neutron disabling, accessible monochromators and range preservation.
5. **Angle selection and simulation phases.** Clicking a monochromator row fills its displayed 2θ into the Instrument field; crystal buttons also support keyboard selection. Simulation lists only phases with atoms, automatically includes a single eligible phase and shows its name without an Include checkbox. Multiple eligible phases retain their Include controls.
6. **Simulation instrument controls.** Share Instrument's live monochromator picker, source updates and anomalous-scattering switch with Simulate a pattern. Neutrons disable the switch. Build the atomic simulation model before resolving corrections so they also apply when starting from WPPF or Le Bail; explicitly selected simulation phases are independent of the fit inclusion flags. Preserve the generated pattern's anomalous factors in project metadata and verify on/off, wavelength and neutron calculations across all three starting methods.

## 2.38.0 — 25 October 2026

1. **Monochromator angles at the current wavelength.** Instrument and range replaces the fixed graphite/Cu hint with a tooltip on both the monochromator label and its angle input. It lists approximate Bragg 2θ for graphite (002), quartz (10-11), Ge (111)/(220), Si (111)/(220) and LiF (200), calculated from the dialog's current λ1 and refreshed after source or wavelength edits. Impossible reflections are marked instead of displaying an invalid angle. The entered monochromator value is kept.
2. **Hover and keyboard help.** Labels and fields can use the existing full-size help popup; focusing the angle input opens the same table as hovering its label. The user guide distinguishes these current-λ1 values from its static weighted-mean Kα reference table.

## 2.37.2 — 25 October 2026

1. **Wyckoff GPU and CPU documentation.** README, About and the user guide distinguish GPU proposals, fitness and acceptance from CPU enumeration, replica exchange, restart control and final coordinate refinement. The closing quench is CPU-controlled but still evaluates fitness on the GPU. Wyckoff requires WebGPU and has no CPU-only search fallback; charge flipping and parallel-tempering fits retain theirs.
2. **Restarts, progress and stopping.** Document the initial start plus reseedings, counts per full-search wave and per Z, one-start screening, the closing work after the generation counter, cooperative Stop and immediate second Stop, and the retained History log. Explain CPU/GPU fitness agreement and its limits.
3. **Consistency.** Correct the claim that fitting cannot run without WebGPU, cap the documented screening work at the requested iterations, and synchronize the application and documentation versions. The previous correction and its regression tests are included in this release commit.

## 2.37.1 — 25 October 2026

1. **Wyckoff restart counts.** The form silently clamped every value above 10 to 10 while leaving the typed value visible. Positive whole-number counts now reach the worker and the GPU search unchanged, with validation at every entry point. Every full-search wave runs the requested count; screening still uses one start. Invalid counts are reported instead of rounded or replaced. CPU control and final refinement remain part of the WebGPU search.
2. **Plot controls.** Adding an anchor updates the Anchors checkbox as well as its display preference. Autoscale starts hidden, appears after zooming or panning, and hides when the button or a double-click on either linked plot restores the view.
3. **Keyboard navigation while busy.** Starting a calculation focuses Stop when available, otherwise the workspace; Tab and Shift+Tab remain available. Busy updates preserve navigation focus, and completion restores the original control when focus stayed there. Editing remains guarded.
4. **Markup and labels.** The Datasets calibration action is named Profile with an explanatory tooltip; help refers to Profile too. A JavaScript-disabled message replaces an unusable silent page, and the fit result no longer contains a redundant nested tab panel.
5. **Validation.** Regression coverage checks restart validation and worker forwarding, a real GPU search completing 20 starts with CPU fitness cross-checks, linked plot resets, anchor-checkbox synchronization and busy keyboard navigation.

## 2.37.0 — 25 October 2026

1. **Phases as accordions.** Every phase is an accordion titled in the colour of its plot, with its space group and number of sites beside the name. The current phase is open with its editor; opening another selects it and the editor moves there.
2. **A shorter Phases bar.** Atomic constraints…, Restraints…, Add atom…, Atoms from CIF… and Fragment… are gone from the top of Phases: Add atom…, Atoms from CIF… and Fragment… are under the atoms of each phase, and Constraints (renamed from Atomic constraints) and Restraints have their sections in the phase. "Edit constraints in Datasets →" now opens the Constraints section there, as the bar button did. The bar keeps New phase…, Read CIF… and Simulate….
3. **A shorter Datasets bar and Refine menu.** Preferred orientation… is removed (the axis is set in Phases, r and its refine box in the dataset's parameters); Refine scales only (shown for Rietveld only) leaves the Datasets bar for the Refine menu as Fit scales only (untick the rest), since it replaces every refinement flag of the selection and is not a one-click action for the top of the panel. Delete the current phase leaves the Refine menu: the × of each phase in Phases → Choose a phase deletes it. The documentation described them under Method and as estimating the scales; it now says where they are and what they do.
4. **Polyhedron moves are a setting, off by default.** The Wyckoff search has a Polyhedron moves (%) field below Shape weight, 0–100, default 0, which is the search of single atoms as before 2.36.0 (2.36.0 used 30 % whenever a rule had a count). The search's own default is 0 too. Measured: on the real PbSO4 pattern the structure is found with 0 % and 30 % alike (and in 2.35.0); on a simulated isolated FeC6 octahedron 30 % solved every run against 2 of 5.
5. **Wyckoff fields without effect are disabled**, with the reason as their tooltip: the density window and Values of Z when Z is typed (no Z is scanned), Shape weight when no rule has a shape, Polyhedron moves when no rule has a count.
6. **Tests.** The Wyckoff search page checks the disabled fields and that the percentage reaches the search. The phase-atoms page checks the bar, the accordions (one per phase, colours, the editor in the current one, selection by opening) and uses the buttons in the phase. The bundled-files test reads patterns only, not molecules or saved projects kept in `test_files/`.

## 2.36.0 — 25 October 2026

1. **Polyhedron moves in the Wyckoff search.** When a distance rule has a count (`Fe C 6 1.85/2.05 octahedron`, `S O 4 1.40/1.60`), 30 % of the proposals move a coordination shell as a unit instead of single atoms: the centre and its nearest partners translated together, the partners rotated about the centre, or the partners snapped to one distance (in the rule's window) and, for a shaped rule, to the ideal shape best aligned with the current shell. Each moved partner is put back on its independent site through the inverse of its symmetry operator and projected on its Wyckoff position; the proposal is scored and accepted like any other, so a shell that does not suit a unit move (shared corners, a special position) only lowers the acceptance. Runs without a counted rule are unchanged. On a simulated FeC6 (P21/c, Z = 4, the octahedron on a general position) five runs of 600 iterations reached a best fitness of 0.93 with an intact octahedron every time, against 0.46–0.84 without the moves, at the same cost per iteration; at 1500 iterations 0.93 every time against 0.06–0.93.
2. **Kernel contract.** The kernel carries the inverse orthogonalisation and the share of the moves in its parameters, and a `POLY_MOVES` marker that the host checks, so a cached older kernel is refused.
3. **Tests.** The Wyckoff search page checks that a counted shell turns the moves on and that bare rules do not.

## 2.35.0 — 25 October 2026

1. **Atoms from CIF.** Phases → Atoms from CIF… (also under the atom table and in the Refine menu) reads the atom sites of a structure CIF into the current phase, replacing its atoms or adding to them; the phase keeps its cell and space group. A CIF in another space group or a cell more than 2 % different is read and said, not refused. Read CIF… still makes a new phase.
2. **Fragment.** Phases → Fragment… puts a molecule (PDB, MOL/SDF, XYZ or Z-matrix) into the current phase: atoms labelled by element (C1, C2 …, numbered past those already there), the centroid at a point of the cell farthest from every symmetry element (editable) in the orientation of the file, or at the coordinates of its own cell for a PDB with CRYST1. Hydrogens are left out by default for X-rays; a rule for every bond and angle of the molecule is added to the restraints of the phase by the same labels, so no atom matching is needed. An atom that falls on a symmetry element is reported.
3. **Molecule files.** MOL/SDF (V2000) is read by the molecule readers (Fragment and the Molecule tabs of both Helpers); the file pickers offered `.mol` without a reader for it and `.gjf`, which was not read either (removed). A PDB CRYST1 cell is read.
4. **Tests.** Node regressions for MOL/SDF, CRYST1, fragment placement (bond lengths kept, general positions, labels, restraints, replace) and atoms from CIF (replace, add, mismatch notes); a browser page (`tests/phase-atoms`) for the buttons, dialogs and Undo.

## 2.34.0 — 25 October 2026

1. **"Start step end" patterns.** A file whose first line is `start step end` followed by the intensities, any number per line (FullProf INSTRM=0, WinPLOTR, EXPO `.dat`, e.g. `test_files/cimetidine/cime.dat`), is read as a constant-step scan. It used to fall to the two-column reader, which took the header as the point (start, step) and each row of counts as a point at 2θ = its first count. The number of values must match (end − start)/step + 1 within 1 %, which keeps three-column x y σ files apart.
2. **Misread axes refused.** A pattern whose 2θ reaches beyond ±180° is refused with a message that the layout was not recognised, instead of loading a pattern up to 2θ = 100000.
3. **GSAS.** STD records are `10(I2,F6.0)`: a filled counter field is no longer read as an intensity of its own, and lines whose trailing blanks were stripped are still read as fixed fields. A two-column file whose title starts with "Bank" is no longer taken for a GSAS bank.
4. **UXD.** `_KEY = value` with spaces is understood; `_2THETACOUNTS`/`_2THETACPS` pairs are read; each range is its own dataset (ranges were appended to the first one's axis); counts per second are multiplied by `_STEPTIME`; Kα2 and its ratio come from `_WL2`/`_WLRATIO`. A broken UXD reports its own error instead of "only 1 usable point".
5. **Rigaku RAS/RASX.** The wavelength is read from `*HW_XG_WAVE_LENGTH_ALPHA1` (quoted); intensities are counts times the attenuator factor of the third column; every scan block of a `.ras` is read (reading stopped at the first).
6. **XRDML and BRML.** XRDML: every scan of a file becomes a dataset, `<listPositions>` axes are read, Kα2 and its ratio are taken with Kα1. BRML: DIFFRAC.SUITE `<Datum>` records are read, with the axis from `ScaleAxisInfo` and the wavelengths from `WaveLengthAlpha1/2` and `WaveLengthRatio`.
7. **Text files.** Wavelengths in the header are read (a title such as "Wavelength 0.79764", the PANalytical CSV keys "K-Alpha1 wavelength", "K-Alpha2 wavelength", "Ratio K-Alpha2/K-Alpha1"); decimal commas (`10,02;1234`) are recognised; a header word such as `2Theta` is no longer read as the number 2; in `.xye` files a standard uncertainty of 0 takes √max(I, 1) with a warning instead of rejecting the file; UTF-16 files are decoded.
8. **Binary files** (Philips `.rd`/`.sd`, binary `.raw`) are refused by name, with the formats to export to, instead of failing in a text reader.
9. **Project ids.** A project in which a dataset was saved without an id (older files) gave that dataset the id a later dataset brought with it, so two datasets shared one id (selection, parameter links and global-fit results then mixed them up). Saved ids are now reserved first.
10. **Undo keeps the intensities.** An undo, or Restore before, left the Le Bail / WPPF datasets without the intensities of their last fit (empty intensity table, HKL export disabled until the next fit), although project loading and switching methods bring them back. Restore points now keep them, as they keep the fit statistics.
11. **Style and housekeeping.** The space-group-test set chips wrap without `!important`; the print layout hides the panels without it (and hides the panel grip); the busy cursor is the one documented exception. A busy-cursor rule for plots that never applied and the update of a Restore-points note that no longer exists were removed. Two test files with mixed line endings were made uniform.
12. **Tests.** Node regressions for both fixes; `tests/density-boundaries.test.cjs` now runs with the other Node suites in GitHub Actions; CLAUDE.md lists every browser page and describes the line endings as they are. Node regressions for each reader; a browser page (`tests/file-readers`) for XRDML and BRML; the bundled-files test reads `test_files/` subfolders. Three browser pages that failed against the current interface were brought up to date: `constraint-refine` waits for the typing pause of constrained values (2.33.0), `solve-fixes` reads the formula and Z hints from their tooltips (2.29.1), and `ui-consistency` uses the Method tab's Fit button (the Datasets one was removed).

## 2.33.3 — 25 October 2026

1. **One look for the help buttons.** The "?" buttons of Constraints, Restraints, the formula unit and Fourier maps were small rectangular buttons; they now share the round style of the command-bar "?" (one `.help-q` rule with `.cmd-help`), on the line of their help text.
2. **Example rules read as suggestions.** The example rules shown in the empty Restraints and Wyckoff Distance constraints boxes (and the other rules boxes) are faint and italic, so they no longer look like entered rules.
3. **Help no longer truncated.** The "?" help opens in a popup at the button (on hover or keyboard focus) instead of the native tooltip, which browsers cut short: the Restraints rules help (about 3000 characters) is shown whole, with its paragraphs and list, and scrolls when it is taller than the window; the popup stays open while the pointer is on it, closes with Escape, and opens inside a dialog when the button is in one.

## 2.33.2 — 25 October 2026

1. **Factor tooltip.** In the Wyckoff constraint Helper (Suggest tab), the Factor label and its value show "shortest contact = Factor × (covalent radius of A + covalent radius of B)" on hover.

## 2.33.1 — 25 October 2026

1. **Helper placement.** The Helper button sits to the right of its rules box, in Datasets / Restraints and in the Wyckoff search Distance constraints, instead of below it.

## 2.33.0 — 25 October 2026

1. **Wyckoff constraint Helper.** A Helper button under Distance constraints opens the tabbed Helper of the restraints, acting on the elements of the formula unit: Geometry (coordination shell with count or shape, nearest-distance window, shortest contact), Molecule (bonds by element pair from a PDB, XYZ or Z-matrix: counted when every centre has the same number of neighbours, nearest otherwise) and Suggest (shortest contacts from the covalent radii). Add collects into one box with duplicate/conflict pruning and the kernel-limit check; Copy writes to the clipboard and never changes the constraints box; Close closes it. The restraint Helper's Cancel button is now Close as well, since it never had anything to cancel. The button is disabled, with the reason as its tooltip, while there is no readable formula unit or a calculation runs.
2. **Tests.** A browser page (`tests/wyckoff-helper`) covers the disabled state, element choices, the three generators, pruning, Copy and Cancel.

## 2.32.0 — 25 October 2026

1. **Restraints after atom edits.** Deleting an atom (or a site/space-group change that loses one) removes the restraint rules that name it, with a Log entry and a warning, instead of leaving rules that stop every Rietveld fit. Renaming an atom renames the A and B of each rule that resolved to it, including case-insensitive matches; the rest of the line (numbers, comments) is left alone.
2. **Restraint settings.** Changing weight, σ distance or σ angle while the saved rules are invalid shows the error and restores the inputs instead of throwing an uncaught exception.
3. **Directional counted rules.** Counted and geometry rules are about the B around A: `Fe1 O1 6 … oct` and `O1 Fe1 2 …` are no longer rejected as duplicates. Nearest-distance rules (`A B -`) stay one per unordered pair, since the distance is symmetric.
4. **Neighbour search.** The cells searched on each axis follow the reciprocal metric (exact in strongly oblique cells; the shortest edge underestimated the reach). Symmetry images within 1e-4 across a cell face are merged. When fewer neighbours than a rule needs lie within the first radius, the search widens instead of using a constant distance at the radius (which gave a penalty with no gradient).
5. **Restraint derivatives.** Variables of other phases that drive a restrained parameter through a link or atomic constraint are differentiated as well.
6. **Constraint dependencies.** The independent parameter of an equivalence, or a term of a constraint equation, may be a parameter-link target (or source): the dependency is followed through instead of failing with "Conflicting constraint dependencies". Circular definitions get a named error.
7. **Removing atoms from constraint equations.** A constraint equation losing an atom is dropped whole, with a warning and Log entry, instead of silently becoming an equation with a different meaning (A + B + C = 1 → A + B = 1).
8. **Copy values.** Copied values are re-aligned to the atomic constraints and parameter links of the datasets they land in, with a warning if they cannot be.
9. **Typing constrained values.** Constrained and linked values typed in Parameters apply once typing pauses (0.4 s), not at every keystroke.
10. **Minor.** Wyckoff-search distance-rule errors give the right line number after blank lines; Copy to a dataset that no longer exists says so; unused restraint-editor code removed.
11. **Tests.** Node regressions cover rename/delete of restrained atoms, ordered counted rules, oblique-cell and boundary neighbour searches against brute force, widened shells, link-driven equivalences and dropped equations.

## 2.31.2 — 25 October 2026

1. **Complete constraints, restraints and links guide.** Add a dedicated Links section covering source/target selection, multipliers, offsets and display units, refinement flags, edits in either direction, limits, dependency conflicts, individual/global fits, removal, method setups and persistence. Add worked occupancy examples, the no-freedom case, and a table distinguishing atomic constraints, soft restraints, exact links, sharing and one-time copies.
2. **Documentation consistency audit.** Correct mixed-site instructions to use the grouped sum checkboxes; distinguish equivalence flags from sum-dependent flags; replace the obsolete Constraints and links location; put limits under Datasets / Links / Parameter links and sharing; explain rejection of invalid constrained edits rather than silent clipping. Clarify that the tabbed Helper collects rules only for clipboard copying and that duplicate pruning does not establish global geometric consistency. Update README, built-in help, section navigation and release markers. Section links have no missing targets or duplicate IDs.

## 2.31.1 — 25 October 2026

1. **Restraints introduction.** Show the short description and question-mark help once above the phase headings, matching Constraints, rather than repeating them inside each phase editor.

## 2.31.0 — 25 October 2026

1. **Dataset layout.** Move Copy from the parameter list to its own final accordion below Links. Replace the restraint-rules accordion with a question-mark tooltip beside a short description of what restraints do.
2. **Tabbed rule scratchpad.** Helper uses Geometry, Molecule and Suggest tabs. Add in each tab generates and merges into one collected-rules textbox below the tabs; it does not modify phase or dataset restraints or create Undo entries. Duplicate and conflicting atom-pair rules are pruned, keeping the first rule and reporting conflicts. Cancel closes the helper; Copy validates and copies the collected list to the clipboard. Only the user's paste into the main restraints textbox applies rules; repeated pastes still trigger the main duplicate validator. Clipboard failures offer a selectable manual-copy fallback.
3. **Validation.** Browser checks cover the final Copy accordion, tooltip, tab switching, all three generators, collection merging, conflicts, clipboard copying, Cancel, main-editor paste validation and Undo. Existing molecule and restrained-fit browser checks continue to pass; numerical tests also check conflict counts.

## 2.30.0 — 25 October 2026

1. **Constraint help.** Replace the GSAS-II rules accordion with a small question-mark help button in the introductory description, retaining its explanations as a tooltip.
2. **Restraints layout.** Phase headings use the same colour markers and method labels as Constraints. Remove the Apply checkbox: any rule in the textbox is applied in Rietveld fits, and clearing the box removes the restraints. Legacy disabled flags no longer suppress nonempty rules. A collapsed explanation covers syntax, counts, shapes, symmetry, windows versus sigma, duplicate rules, fitting, helpers and persistence.
3. **One Helper dialog.** Replace the inline geometry, molecule and structure-suggestion panels with a Helper button opening a modal containing all three. Add and Replace update the active phase and its inline textbox, retain duplicate checks and Undo, and return to the editor when invoked from the phase dialog. Browser coverage checks the modal lifecycle, coloured headings, help placement and existing molecule/fit workflows; a numerical regression verifies automatic application and removal.

## 2.29.1 — 25 October 2026

1. **Unique restraint pairs.** Allow one distance or geometry rule per unordered atom-label pair, resolving label aliases before checking. Direct text edits and refinement validation reject repeated pairs even with different windows, counts, shapes or angular tolerances. Geometry helpers, molecule guides and structure suggestions omit repeated pairs; Add keeps existing rules and reports skipped duplicates. Generated angle-distance rules share the same check, so overlapping fragments and repeated additions cannot double-weight those distances. Regression and browser checks cover reversed pairs, aliases, conflicting geometry rules, overlapping fragments and repeated Add.

## 2.29.0 — 25 October 2026

1. **Restraints editor flow.** Show the editable active-restraints textbox first and keep Geometry helper collapsed below it. The helper proposes rules automatically from the chosen settings; Add validates and appends them directly to the active textbox, preserving existing rules and Undo. Remove the separate Preview rules / Add these rules steps. Numeric-field edits preserve the Add button so leaving a field cannot cancel the pending click. Browser checks cover the ordering, automatic proposals, direct append, validation, Undo and button stability.

## 2.28.1 — 25 October 2026

1. **Wyckoff formula help.** Remove both question-mark help markers beside Formula unit. The label and textbox carry the formula explanation and dynamically updated composition, Z and density guidance as tooltips; warnings remain highlighted on the field and label.

## 2.28.0 — 25 October 2026

1. **Dataset restraints and geometry helper.** Rename Atomic Constraints to Constraints, remove the duplicate internal heading, and add Restraints immediately below it and above Links. Each phase of the inspected dataset has the existing rules, weights, geometry checks, molecule guide and structure suggestions available inline.
2. **Generate fragment rules.** Select a central atom and ordered neighbours, choose a bond, angle, tetrahedron, octahedron, square planar, triangle or linear geometry, and enter distance and angle tolerances. Preview the generated rules and deviations before adding them; edits support Undo. Distinct-label angles become 1-3 distance windows at the target bond lengths, so their angular tolerance is approximate when bond lengths vary.
3. **Symmetry-related shells.** Geometry presets can instead use symmetry copies of one neighbour label. Counted shape rules accept an optional Rietveld-only angular window, e.g. `Si1 O1 4 1.59/1.65 tet angle=3`. Angles inside the window add no penalty; deviations outside use the phase's angle sigma and weight. Existing rules without the suffix retain their previous behavior. Windows are stored in the rule text and follow existing project, report and Undo handling.
4. **Validation.** Regression coverage checks all presets, angular-window conversion, invalid selections, ideal and distorted tetrahedra, and symmetry-shell windows. Browser coverage checks section placement, previews, applying rules, Undo, symmetry modes, validation and disabled controls during calculations; the existing molecule-guide and restrained-fitting browser checks also pass.

## 2.27.0 — 25 October 2026

1. **Constraint refinement and edits.** Sum-constraint refine checkboxes enable or fix all terms together, with one fewer independent refinement variable than terms. Partial flags are shown as mixed, tooltips explain the relationship, and equations at their parameter-limit extremes show when no refinement freedom remains. Valid edits update related values while typing; either end of an equivalence or dataset parameter link can be edited, updating its source and dependents while preserving limits. Invalid edits leave all values unchanged.
2. **Dataset controls.** Copy has independent Values and Refinement flags options, a destination selector for all other datasets or one named dataset, and a Copy button. Atomic Constraints exposes the editor directly; Links is a separate section with parameter limits and sharing beneath it. Remove redundant selection/fit buttons, their unused handlers, and the extra Links title. Scope equation styles so constrained values and refine checkboxes keep their row alignment.
3. **Fourier and structure views.** Periodic density surfaces include equivalent peaks on cell faces and edges. Fourier, charge-flipping and Wyckoff formula help moves to tooltips. Autoscale and Reset view appear only when the view has changed.
4. **Validation.** Add regression coverage for grouped refine flags, constrained edits in both directions, dataset-link propagation, bound-limited sums and periodic density boundaries; add browser pages for constraint alignment and editing. The 96 Node regression tests passed. Browser checks for Fourier maps and constraint alignment passed; the later constraint-edit browser runs timed out.

## 2.26.2 — 24 October 2026

1. **Fourier peak threshold.** The peak list of a Fourier map starts at a setting, Peaks above (σ), default 4 instead of the fixed 2.5 σ, which listed mostly noise in powder maps. The setting is remembered.

## 2.26.1 — 24 October 2026

1. **Set on a structure-solution run.** Restoring a saved charge-flipping or Wyckoff run from History put its intensities back marked out of date (`stale` was saved with the record), so the Structure tab dropped them and the run showed without its extraction. They are now marked current when adopted, and are kept under the phase-and-dataset key as well. `tests/history-stop.html` passes again.

## 2.26.0 — 24 October 2026

1. **Fourier maps.** Commands → Structure has a Fourier map block beside the space-group test, charge flipping and the Wyckoff search, and Results → Structure a Fourier map view. It builds a difference (Fo − Fc), observed (Fo), 2Fo − Fc or calculated map of the selected phase from the WPPF intensities of the selected dataset and the phases of the atoms of its model (the dataset's values or the starting model). The observed intensity of each overlap group is shared among its reflections in proportion to m·Lp·(|Fc|² + ε); one factor puts the amplitudes on the scale of Fc; an FFT on a cubic grid (at most 128³, optional finer grid) gives the map. The isosurface uses the charge-flipping density viewer (level in σ, holes of a difference map, cell, atoms, PNG, JSON). A peak table lists the extrema above 2.5 σ, one per set of equivalent positions, with the nearest atom and its distance; Add atom… puts a positive peak into the phase with the scatterer you name.
2. New modules `js/fourier_map.js` (structure factors, partition, FFT, peaks; no dependency on the page) and `js/rietveld/rv_fourier.js`; Structure results gain a fourth kind, `fo`, with no run history (maps are recomputed on demand and are not saved in projects).
3. Tests: a Node test (a difference map of a Na-only NaCl model finds the Cl site 2.8 Å from Na) and the browser page `tests/fourier.html` (real WPPF extraction, the strongest difference peak on the Cl site, the viewer, the atom-less refusal).

## 2.25.0 — 24 October 2026

1. **Rietveld restraints.** A phase can carry soft distance and angle restraints (Phases → Restraints…), written in the distance-rule language of the Wyckoff search (`Fe1 C1 6 1.6/2.2 oct`, `C1 C2 - 1.38/1.42`, `O1 O1 - 2.4/`) with atom labels instead of elements. Values outside their window add ((value − nearest bound)/σ)² × weight to χ² as extra observations, with σ(distance), σ(angle) and a weight set per phase. They enter the normal equations (numerical derivatives of the restraint rows, so uncertainties include them) and the degrees of freedom; Rwp and the other agreement factors stay those of the pattern. The symmetry images of the second atom are searched. Parallel tempering with restraints runs on the CPU. They are saved in projects, restore points and the reports.
2. **Molecule guide.** Reads a PDB, XYZ or Z-matrix molecule (or pasted text) and writes a rule for every bond and every 1-3 distance (the angles), matching the atoms of the file to the atoms of the phase by name or by order and leaving out atoms the phase does not have. **Suggest from the structure** writes counted rules from the contacts of the current model.
3. **One rule parser.** The parser of the Wyckoff distance constraints moved unchanged into `js/distance_rules.js`, shared with the restraints. New modules `js/atom_restraints.js`, `js/molecule_rules.js` and `js/rietveld/rv_restraints.js`; the fitting worker loads the first two.
4. Tests: Node (shared parser, restraint geometry through the symmetry images, a restrained fit, projects/undo/rename, molecule files) and the browser page `tests/restraints.html`.

## 2.24.8 — 24 October 2026

1. **Philips UDF RawScan.** Read packed intensity rows using DataAngleRange and ScanStepSize, with LabdaAlpha1/2 and RatioAlpha21 metadata. Preserve all complete points and warn when the stated endpoint disagrees or the closing marker is missing. Recognized UDF/RD/SD files no longer fall back to interpreting counts as angle/intensity pairs when parsing fails. Regression coverage includes sfmo_x3_299.udf (9,574 points).

## 2.24.7 — 24 October 2026

1. **GSAS channel-count mismatches.** Load complete numeric points when fewer points are present than the BANK header declares, and show a warning with both counts. Do not pad missing intensities or uncertainties. Malformed numeric records, incomplete ESD pairs and fewer than two complete points remain errors.

## 2.24.6 — 24 October 2026

1. **Observed patterns without a phase.** Opening patterns selects the Plots results view. A saved background-subtraction setting no longer hides observed points when a calculated background is unavailable: show raw intensities with an explanatory note and matching axes. Apply subtraction only when all plotted datasets have calculated backgrounds, outside the multi-dataset overview. Phase requirements still apply to refinement.

## 2.24.5 — 24 October 2026

1. **Automatic WPPF intensity preparation.** Remove the manual Extract intensities button. Structure selects the phase/dataset source and automatically prepares its uncertainty and correlation information after WPPF fitting, including multiphase datasets. Cache prepared sources by dataset and phase, and show availability or the fit prerequisite. Failed preparations do not retry continuously.

## 2.24.4 — 24 October 2026

1. **Structure preparation.** Move phase/dataset selection and extraction into an Extract intensities accordion. Show the extraction prerequisite beside the button, and explain that ADDSYM does not need intensities. Keep manual extraction available for single-phase datasets as well as automatic extraction after WPPF fitting.

## 2.24.3 — 24 October 2026

1. **Distinct application header.** Give the Powder 6 command bar a muted blue background in light mode and a slate-blue background in dark mode, with a stronger bottom rule and subtle shadow. The title uses the accent colour to match its diffraction icon. Panel toolbars retain their neutral surface.

## 2.24.2 — 24 October 2026

1. **Help theme switch.** Replace the help's plain theme button with a Light/Dark slider in a sticky top-right toolbar, matching the main program's toggle. Both labels remain visible and the selected mode is emphasized. The contents and anchor scrolling account for the toolbar; it is hidden when printing.

## 2.24.1 — 24 October 2026

1. **Help appearance.** Documentation uses the program's saved theme before first paint, with a user-controlled theme switch. Switching the help theme affects the current help page; reopening follows the program again. Remove reading-width caps so paragraphs, notes and examples use the available content width.

## 2.24.0 — 24 October 2026

1. **One dataset selection section.** Remove Selection and batch and its duplicate editable table. Move fit mode, Fit selected datasets and selection actions into the Datasets accordion. Each dataset row has Edit for its name and colour, with automatic theme colour available. Custom colours apply to plots and headings and survive project saving, Undo and calculation History.

## 2.23.1 — 24 October 2026

1. **Palette refinement.** Spread the early dataset colours across blue, burnt orange, teal, purple, ochre, magenta and olive, with corresponding light colours in dark mode. Phase colours follow the same palette. Darker amber active anchors, stronger fixed anchors, background curves and axis colours improve plot annotation contrast in light mode; dark-mode axes and fixed anchors are brighter. Existing solid/dashed curves and filled/hollow anchor markers retain their roles.

## 2.23.0 — 24 October 2026

1. **Wyckoff proposals.** Three quarters of MCMC proposals move one free independent Wyckoff site (and its entire symmetry orbit); the rest retain collective moves. Fixed positions and padding are excluded from single-site selection, and untouched sites retain their exact coordinates. This reduces the coupled rejection of otherwise useful local moves in larger structures.
2. **Panel surfaces.** Datasets, Phases and Method action headers, fit-result run selectors and Structure result tabs share the theme's chrome background in light and dark mode.

## 2.22.7 — 24 October 2026

1. **Selection and batch fit mode.** Show Individual / Global when at least two datasets are selected, synchronized with Commands / Method. The Fit selected datasets button respects that mode instead of forcing individual fits. Updated the instructions to refer to dataset accordions.

## 2.22.6 — 24 October 2026

Removed the redundant Refinement parameters button from Selection and batch; it only reopened the Datasets view without revealing or scrolling to the editor.

1. **Interface consistency and readability.** Shared control borders have stronger contrast in both themes; the default light-theme dataset and phase colours meet normal-text contrast on the workspace; placeholders use readable text contrast; editable parameter fields have visible boundaries. Small labels and structure-report tables use the shared type scale (at least 12 px), with larger default plot labels. Scientific values retain tabular numerals and monospaced parameter editing.
2. **Keyboard and assistive technology.** Focus indicators retain a visible outline even on controls with their own shadows and in forced-colour mode. Dialogs expose their visible title as their accessible name, the workspace skip-link has a focusable destination, History tabs support arrow keys/Home/End with one tab stop, and Structure tabs explicitly identify their panels. Switching dataset accordions retains keyboard focus, and their headings remain available for inspection while a calculation runs.
3. **Compact actions.** Remove, help, previous/next and parameter sharing controls use consistent targets of at least 24 px; parameter grids accommodate their larger actions. Fixed parameters no longer fade their sharing controls below readable contrast.
4. **Browser checks.** Added an interface consistency page covering light/dark text and control contrast, focus outlines, selected-dataset accordions, History keyboard navigation, Structure panel relationships, dialog titles and desktop/tablet/narrow viewport overflow.

## 2.22.5 — 24 October 2026

1. **Selected dataset accordions.** Show a coloured accordion heading for every selected dataset instead of only the active one. Opening a heading selects that dataset for inspection and places the parameter editor under it, without changing the fit selection.

## 2.22.4 — 24 October 2026

1. **Dataset list controls.** Hide the Fit / plot datasets selector and Delete selected button with fewer than nine datasets, matching the Find field. Individual selection checkboxes and row remove buttons remain available.

## 2.22.3 — 24 October 2026

1. **Datasets layout.** Datasets, the coloured active dataset name, and Selection and batch are accordions without white outer cards. The active dataset name appears only in the accordion heading; use the Datasets list to switch patterns. Each list row has a remove icon matching the phase remove controls, with confirmation and undo.

## 2.22.2 — 24 October 2026

1. **File menu cleanup.** Removed the duplicate Report (PDF) entry; PDF reports remain available from the Report button in the top bar.
2. **Instrument profiles and File menu cleanup.** Instrument-profile reading and saving remain in the dataset's Profile dialog; the duplicate File entries and their separator have been removed, along with the sample-broadening Load and Save entries. The dialog is titled Instrument profile and uses Read instrument profile / Save instrument profile; the Datasets button is labelled Profile to save space.

## 2.22.1 — 24 October 2026

1. **Calculation method accessibility.** The Le Bail, WPPF and Rietveld selector in Commands → Method is now a radio group instead of tabs referring to the separate Results panel. Its appearance is unchanged; all four arrow keys move focus and select the next or previous method, wrapping at either end. The selected result run remains independent.
2. **Cancellation, Structure tabs and project validation.** Escape stops a running calculation even from inspection controls; Structure result tabs support Left/Right, Home and End; project import rejects uncertainty and weight arrays whose lengths differ from the observations. These corrections were committed immediately before this release.

## 2.22.0 — 24 October 2026

1. **Le Bail ran twice the maximum iterations.** A Le Bail fit has two stages (a WPPF start, then the cycles) and each was given the whole budget, so 30 iterations could become 60. Maximum iterations is now the budget of the whole fit: the WPPF start uses at most half and the cycles what it left (at least one).
2. **Phases: starting model and datasets.** A phase holds the starting model and each dataset its own values (a fit changes the dataset's, an edit in Phases the starting model's), which is by design but left no way to carry one into the other. Under the atoms: **Starting model → datasets…** copies the cell and/or the atoms of the starting model into every dataset holding the phase, or one of them (fit results cleared, flags kept; the atoms also go into the saved Rietveld model of a dataset fitted by another method now); **Dataset → starting model…** makes a dataset's values (its fitted ones after a fit) the starting model. Both are undone with Ctrl+Z.
3. **Phases: a Structure block** (an accordion under the atoms) draws the structure of the phase with the viewer of Results and Structure (picture, coordination, distances), for the starting model or a dataset's model, chosen in Model.
4. **Find higher symmetry converts at once.** Its button is **Convert** and it applies the conversion it reported (setting, axes, origin, tolerance, atomic source) instead of opening the Convert… dialog again with an empty Find box; the dialog opens only when the conversion needs a look (atoms off the new symmetry, a dataset whose positions lack it), and then with the reason.
5. **Wyckoff search: a summary in the Log.** The Log no longer lists every Z, wave, restart and assignment as the search runs; at the end it shows the result of each Z, the ranking, the values of Z that failed and the warnings, and says how many lines the whole search log has. The whole log is kept in History (Search log).
6. File → **Read project…** (was Open project…), like Read patterns… and Read CIF….
7. Tests: the Le Bail iteration budget; the Phases Structure block and both copy buttons; the ADDSYM pages follow the direct conversion; the Wyckoff page checks that the Log is a summary and reads the whole search log from the result.

## 2.21.0 — 24 October 2026

A review of the refinement, charge-flipping and Wyckoff mathematics.

1. **Charge flipping: the phase relation of the space group had the wrong sign.** The map is ρ = Σ F exp(+2πi h·x) (the inverse transform of the worker), for which F(hR) = F(h)·exp(+2πi h·t); the starting grid and the symmetrisation (CPU and WGSL) used exp(−2πi h·t), i.e. the operators (R, −t) of the inverted group. Groups whose translations are 0 or ½, and centrosymmetric groups with the origin on −1, were unaffected; with 4₁, 3₁, 6₁ screws, d-glides or origin choice 1 the iteration solved the enantiomorph or an origin-shifted copy, and only the search over both hands and many origins in Build structure put it right. On a P4₁ test the map now obeys the group as written (residual 4·10⁻²⁶ against 6·10⁴ for the inverted relation) and the hand search keeps hand +1.
2. **Transparency estimates had the wrong sign.** A penetrating beam moves the peaks to lower angle, Δ2θ = −sin 2θ/(2µR), so with Δ2θ = t sin 2θ a real specimen has t = −1/(2µR). The tooltips gave µeff = 1/(2Rt) for t > 0 and an expected t90 = +1/(2Rµ90); both now use the physical sign (the GSAS-II export already did).
3. **A failed WPPF intensity solve set every intensity to zero without a word, and it failed on ordinary patterns.** Root cause: the modified Cholesky of the intensity normal matrix accepted pivots down to 1e-14 × max(1, diagonal), which is absolute when the diagonal is below 1 (as it is with 1/y weights) and lets nearly dependent columns through; their tiny pivots amplified the rounding of every later row until the factor overflowed (10¹⁹⁸ on a triclinic test pattern whose last reflections are cut by the end of the range), every solve on that pattern failed, and the fit carried zero intensities. A pivot at or below 1e-8 of its own diagonal (the repair value) is now treated as a dependency and repaired; the factor stays bounded (24 repairs, residual 5e-16 on that pattern). In addition the non-negative solve is retried from a cold start, and if it still fails a trial step is refused and a fit or an evaluation stops with a message, instead of returning (or handing to charge flipping and the Wyckoff search) an extraction of zeros.
4. The largest displacement step per iteration was 100 (0.1 rad·cos θ, up to 5.7°); it is 2 (about 0.11°, like the zero point's 0.1°).
5. Wyckoff search, imported reflection files without an Lp column: Fo² was divided by m·Lp but σ was not, so the weights were wrong by (m·Lp)², differently for every reflection. σ is now scaled with its value, as it already was when the file carries Lp.
6. With parameter links in a dataset that has WPPF phases, the marginal uncertainties of the intensities used the projection of the variable's own column, while its Jacobian column carries the linked columns too; the projections are now combined the same way.
7. **Anomalous dispersion.** Datasets → Instrument takes f′ and f″ per element at λ1 (`Fe -3.36 3.20, O 0.05 0.03`, from tables for the wavelength; no values are invented). They enter the Rietveld structure factors as f₀ + f′ + i f″, Friedel-averaged as a powder line requires, (|F(h)|² + |F(−h)|²)/2, with exact derivatives, in the CPU model and the WebGPU PT kernel alike. Saved with the instrument in projects, restore points and the History; without entries every number is bit-for-bit what it was.
8. **The SL/HL asymmetry is included in the peak area.** The asymmetry stretches one flank and compresses the other, which changes the area, while the normaliser was that of the symmetric peak (up to 17 % off for strong low-angle asymmetry). The change is integrated (Gauss–Legendre panels to the clamp point, closed-form tails beyond), within 5·10⁻⁴ of a brute-force integral, in profile.js and the WebGPU PT kernel. The untruncated-area normalisation itself is kept: it recovers the full integrated intensity while the background takes up the tails beyond the window.
9. **Wyckoff search and coordinate refinement: overlapped groups are weighted with the WPPF covariances.** The variance of a group's summed intensity was the sum of the members' variances; overlapped WPPF intensities are strongly anti-correlated, so the sum is far better determined (on a synthetic pair with correlation −0.99, σ of the sum 3.2 instead of 39.7). The extraction now keeps the covariances of overlapping reflections (from the selected inverse and the Woodbury term), and both the search and the final refinement use Σσ² + 2Σcov (one shared function, so they weight the same residual).
10. Wyckoff search: the scattering table used the d of a group's first member for every member; each reflection now has its own.
11. Wyckoff search: structure factors are summed over one image per centring class (the centring translates are flagged in the generated-atom table and skipped in the reflection sums; the contacts still see the whole cell): the hottest loop of the search does a half of its work for C, A, B and I lattices, a third for R and a quarter for F. Reflections the centring forbids are left out of the fitness (their calculated intensity is zero in the full cell).
12. Wyckoff enumeration: four-coordinate oxygen is no longer assumed tetrahedral (it is square planar on an inversion centre in NbO), so an "O … 4" constraint without a stated shape no longer removes such assignments.
13. Parallel tempering: a sweep is now one proposal per refined variable per replica, then one round of exchanges (it was one proposal per replica, so 200 sweeps moved each of 30 variables about seven times). The default is 50 sweeps; the run time of a sweep grows with the number of ticked parameters.
14. Comments and documentation: the Le Bail description matches the code (the areas are held during a cycle and in its Jacobian), the derivatives of cell, profile and geometry are central differences, and a stale note that the WPPF solve has no non-negativity constraint is corrected.
15. Tests: the WPPF solve on the near-singular triclinic pattern, the CF phase relation on P4₁, the anomalous structure factor against an explicit Friedel average, the asymmetric area against a brute-force integral, the centring reduction of the Wyckoff tables (C, R, F), the σ and covariance scaling of the observations and the group variance, the transparency sign, and a WebGPU PT case with f′ and f″.

## 2.20.0 — 24 October 2026

1. Excluded regions are rows in the style of the background anchors: **From** and **To** 2θ boxes, an **Apply** tick, a **×** that removes the zone, and one header over the columns. **Add zone** (formerly Exclude…) opens a window for the start and the end angle. Unticking Apply keeps the zone in the list but takes it out of the fit, the pattern shading, the extraction and the statistics (the zone moves to `inst.exclOff`), to compare fits with and without it; ticking it brings it back. The zones kept aside are saved in projects, restore points and the History, and a project of an earlier version has none. The command Excluded regions of selected… (one text for all zones) and Ctrl+Shift+drag on the pattern still work on the zones applied.
2. Structure: the two notes above the box (what the pane does, the WebGPU budget) are one paragraph; a **warning** appears when no WebGPU is found, pointing to Troubleshooting. The sentence "Single-phase WPPF: …" and the status line are gone (the Extract button's tooltip says what is missing or how the WPPF fit ended; the bar of phase, dataset and Extract is hidden for a single phase, as the extraction is automatic after the WPPF fit, which the documentation now says). Troubleshooting lists how to switch on the browser's hardware (video) acceleration for Chrome, Edge, Firefox and Safari, and the other causes of a missing WebGPU.
3. Datasets: the search box of the datasets list appears from nine datasets. The accordion of parameter limits and sharing no longer starts with a blank space, a line and a title that repeats its own.
4. A uniform look. One spacing scale (`--sp-1…5` = 4, 8, 12, 16, 24 px) and one side margin of the panels (`--inset`) replace the padding of 10, 12, 14, 16, 18, 22 and 26 px that had grown panel by panel, and the command panel no longer overrides the paddings of the stage; every tab bar is `--tab-h` high (it was 38, 39, 40 and 44 px); buttons, segmented controls and header buttons share one padding; the datasets list is an accordion like the others. Three shadows (`--shadow-1`, `--shadow-pop`, `--shadow-3`) replace seven; dialogs, menus and the space-group browser share one box, one head and one foot; the two round help buttons, the header buttons, the two progress tracks, `.hint` and `.note`, `.warn` and `.sv-warn` are one rule each, and the `.sg-btn` buttons are plain buttons. The 28 selectors by `#id` are classes (an id is for the script); the conventions are in CLAUDE.md.
5. The hint of the Charge flipping accordion no longer says "in the worker of powder5" (a note for the developer); it says it runs on the GPU where there is one, otherwise on the CPU.
6. Tests: zones (add, apply, edit, refuse a zone of no width, remove, undo, kept in the instrument copy and the project), and a Node test that the zones kept aside never reach the fit.

## 2.19.0 — 24 October 2026

1. Settings: every box has one width, whatever the label (a long label wraps onto two lines), and the label and box columns follow the width of the panel.
2. Datasets → Background (spline): one header (Anchor, 2θ, Intensity, Fit) instead of a label on each row; the 2θ and Intensity boxes are the same box (the intensity box lost its look when the anchor was not refined); a **×** on each row removes that anchor (the same removal as Ctrl+click on it, with undo; at least two anchors stay).
3. The parameter rows of Datasets, the anchor rows and the table of parameter limits and sharing take their column widths from the width of the panel (flexible columns instead of fixed pixels), so the Parameters no longer need a horizontal scroll bar when the panel is narrow. The limits table is smaller (smaller boxes and type, "Shared" for the long column title, a dash for the parameters that always have one value per dataset).
4. Stylesheet clean-up for a consistent look: the font sizes follow one scale (`--fs-xs` 11, `--fs-sm` 12, `--fs-md` 13, `--fs-lg` 14, `--fs-xl` 15, `--fs-h` 17, `--fs-xxl` 20 px; the halves, 11.5 12.5 13.5 14.5, join the nearest); the radii, the control heights and the dialog backdrop are tokens; the red of `.load-error` and the white of the danger buttons are the theme's `--err` and a new `--on-err` (the danger buttons were white on light red in the dark theme); `--accent` is `--blue` in the rules; cards, accordions and the Structure bar share one box rule; 51 rules of selectors no page uses any more (the old Fit side panel, the calculation cards, the Delete button style, …) and five `[hidden]` rules that the global one makes redundant are removed; the minified block at the end of the file is written like the rest and put in its place before the narrow-window rules, which are merged into one 920 px block. The conventions are in CLAUDE.md.
5. Tests: the anchor table (header, remove buttons, same boxes for X and Y, removal keeps the other heights, two stay, undo), the one width of the Settings boxes and the limits table fitting the panel.

## 2.18.0 — 24 October 2026

1. The **Mode** selector (Individual / Global), its separator and its explanation are hidden while one dataset is selected, as Global is not available then; they appear with two or more.
2. The help text of the fields of the Wyckoff search, the charge-flipping form and Settings is now a tooltip on the label and on the box (the long distance-constraint syntax included), not a line under the box, so a label is always level with its box. Labels that have a tooltip show the help cursor.
3. Phases: the note over the phase list no longer promises that a double-click inspects the phase in Phases (the list is already in that tab, so the double-click and the Enter key did nothing more than a click); both are removed.

## 2.17.0 — 24 October 2026

1. ADDSYM finds the symmetry of a structure refined in P1. A converged P1 Rietveld refinement of PbSO4 (24 free atoms, from a start 0.1 Å off) was recognised as Pnma only at 0.75 Å, beyond the 0.5 Å the scan stopped at, so the report said there was no other symmetry. The scan now runs 0.05, 0.1, 0.2, 0.3, 0.5, 0.75 and 1 Å. When the entered tolerance finds nothing higher but a larger one does, the report names the group, the tolerance and the largest atom move, and a **Use … Å** button sets the tolerance. The hint explains that atoms refined from powder data scatter, and a symmetry operation can need about twice that scatter.
2. Structure pane: the two notes above the box (what the pane does, the WebGPU budget), the box and the three methods now share one left edge; the box lists its facts on separate lines (single phase and its source, then the state of the WPPF fit) instead of one run-on sentence.
3. The three methods of the Structure pane (Space group, Charge flipping, Wyckoff search) start closed in every session; what is opened afterwards is still remembered until the page is closed or reloaded.

## 2.16.3 — 24 October 2026

1. Opening a project checks the archive before using it: `project.json` must be valid JSON and a plain object, observation sets must carry their column lists, a column's declared length must be a plain non-negative number that matches the stored data (and is refused before any memory is allocated when absurd), and the numbers of sets and the size of `project.json` are bounded. A damaged or hostile file now fails with a message instead of a `TypeError` or an out-of-memory error. Observation keys are held in a prototype-free map, so a key such as `constructor` or `__proto__` is an ordinary key.
2. Two errors that were swallowed silently are now reported: a failing result callback of the ADDSYM symmetry sweep goes to the browser console, and a symmetry result that cannot be drawn while the other tolerances are checked is written to the Log.
3. Tests: `tests/numerics.test.cjs` checks cell volumes, d-spacings (cubic, hexagonal, orthorhombic, monoclinic), the Lorentz and polarisation factors and the skyline Cholesky, product and non-negative least-squares solvers against closed-form values; `tests/project-unpack.test.cjs` checks the archive validation. A GitHub Actions workflow (`.github/workflows/tests.yml`) runs the Node suites on every push.

## 2.16.2 — 24 October 2026

1. The View / Inspect line under the plot toolbar is hidden unless two or more datasets are selected (and on the Plots tab): with one dataset, Overlay, Overview and Inspect one dataset are the same picture, so its selector, its stepping arrows and its "1 dataset(s) selected" note were only noise. It returns as soon as a second dataset is selected.
2. The documentation now says what the three views are: Overlay (datasets on the same axes, each with fit and difference, a sample of them beyond the Maximum plots setting), Overview (one thin normalised trace per dataset, stacked, without fit curves or anchors, for long series) and Inspect one dataset (full detail of one).

## 2.16.1 — 24 October 2026

1. The plot toolbar checkbox **Backgnd subtract** is now **Subtract** (its tooltip still says what it subtracts), so the row with the Save PNG button is shorter. Three sentences of the start page, the documentation and the README that still offered "saved groups" (removed in 2.12.0) now point to All datasets and Shift+click ranges.

## 2.16.0 — 24 October 2026

1. A cleaner window. The **Commands** and **Results** headings above the two tab rows are removed (the tabs already name each panel; the panels keep their accessible names). The plot's help line ("Drag: zoom; Shift-drag: pan…") is removed from under the toolbar and replaced by a small round **i** at the right end of the first toolbar row, on the line of Linear / √I / log I. Hovering it, or tabbing to it, opens a tooltip listing every mouse control of the plot: drag, wheel and Alt+wheel, Shift-drag and right-drag, double-click, Ctrl+click anchors, right-drag an anchor, Ctrl+Shift+drag exclusions, legend clicks. The icon stays at the top right when the toolbar wraps.
2. Every session starts as a Cu X-ray tube (Kα1 1.540598 Å, Kα2 1.544426 Å, ratio 0.5, tube polarisation). The instrument of the previous session, kept in the browser, used to become the start of the next one, so after a Co tube, neutrons or an opened project a new pattern began with that instrument. The other remembered settings are kept. A pattern whose file gives a wavelength or radiation, the Instrument dialog and an opened project still set it as before.
3. Tests: the plot "i" (position on the first row, right edge, accessibility, tooltip text, hidden until hover or focus, inside its panel) and the absence of the headings and of the help line; a stored neutron instrument does not survive a restart.

## 2.15.0 — 24 October 2026

1. Histogram matching (added in 2.13.0) is removed from charge flipping: the option, its worker and GPU code, its tests and its documentation. Measured atom by atom on PbSO₄ powder-like data with a known answer, charge flipping already finds every Pb and S and 14–16 of the 16 O without it, and with it finds 11–15 O; on small P1 test structures it changed nothing. Its higher map correlation came from a smoother map, not a more correct one. In 2.13 a matched cycle could also become the kept map, because its R is lower without the map being better. The charge-flipping worker and kernel are back to their 2.12.1 state.
2. Kept from 2.13: the volume per atom (16 Å³) and the group-order preference of the Wyckoff Auto Z live in `js/wyckoff_limits.js`.

## 2.14.1 — 23 October 2026

1. Read structures (CIF)… is now **Read CIF…**, in the Phases toolbar and the File menu, to save space; messages asking for a phase say the same. Atomic constraints… keeps its name: "Constraints" alone would be confused with the parameter links between datasets and the Wyckoff distance constraints.

## 2.14.0 — 23 October 2026

1. Wyckoff search: **Shape weight** (default 1, 0–10) sets how strongly the angles of shaped shells count, as a multiple of the bond penalty; 0 switches the angle term off and keeps the shape's site-symmetry filter. It travels in the kernel's spare parameter slot; the Log states it when a shape is used. Its range and default are in `js/wyckoff_limits.js`.
2. Documentation: the penalties table gives every term as the kernel computes it, including that the bond penalty (0.10) is divided by the number of neighbour slots charged across the cell and the coordination penalty (0.03) by the number of counted centres, the 0.25 Å softness and the flat charge of 5 for an empty slot, the shape term and a worked comparison, the 0.2 to 4.0 ramp, and that the weights steer the search but never rank its results.

## 2.13.1 — 23 October 2026

1. Wyckoff distance constraints accept shortened shapes: two letters or more of a shape's name, when they belong to one shape only (`lin`, `tri`, `tet`, `sq`, `oct`, or `li`, `tr`, `te`, `oc`). The constraint box shows an example with a shape (`S O 4 1.40/1.60 tet`) in its placeholder and its hint.
2. Histogram matching with Z on Auto takes the Z of the Wyckoff solution of the same intensities, else the Wyckoff search's own Auto rule (density window, the multiples of Z the positions allow, nearest 16 Å³ per atom, favouring divisors and multiples of the group order), instead of a separate 18 Å³-per-atom estimate. The note under the checkbox and the Log say which Z was used. The 16 Å³ and the group-order nudge now live in `js/wyckoff_limits.js`, read by both.

## 2.13.0 — 23 October 2026

1. Charge flipping: **Apply histogram matching** (off by default). Every 5 cycles from cycle 10 the flip is replaced by matching the map to the density histogram expected for the cell contents (Zhang and Main 1990; with charge flipping on powder data, Baerlocher, McCusker and Palatinus 2007). The target comes from two random structures of the formula unit × Z (typed, or estimated at 18 Å³ per non-H atom) with the X-ray scattering factors or neutron lengths of the elements, on exactly the reflections of the run, with the overall B of a Wilson plot of the data. The matched map keeps its mean and σ. The GPU (four new kernels) and the CPU do the same arithmetic; the GPU map agrees with the CPU reference after the first matching step (correlation 0.994 on a synthetic P1 structure). The Log names the target, and the results give the schedule, atom count and Wilson B.
2. Wyckoff search: a counted distance constraint may end with a shape, `linear`, `triangle`, `tetrahedron`, `square` or `octahedron` (`S O 4 1.40/1.60 tetrahedron`). The kernel keeps the vectors of each centre's nearest partners and charges the angles between them against the shape's, holding the polyhedron within that centre's own shell. The shape also activates the existing site-symmetry filter for elements it could not infer (a stated tetrahedron keeps Cu off inversion centres; a stated square does not). It costs no extra rule or slot, and a run without shapes compiles the kernel without the vector scratch. The count must match the shape, and an upper distance is required.
3. The shape definitions (names, counts, kernel codes, accepted words) are in `js/wyckoff_limits.js` with the other Wyckoff limits. The kernel's rule records have seven fields (the geometry code), and a cached older kernel is refused by its missing marker.
4. Tests: Node checks of the histogram target (Wilson B, skewed atomic distribution), of the matching step (rank order, mean and σ kept, quantiles imposed), of the CPU search with matching, and of the shape packing and filter; `tests/cf-histogram.html` compares GPU and CPU matching and runs a full GPU search; `tests/wyckoff-search.html` also runs a shaped shell on the GPU.

## 2.12.1 — 23 October 2026

1. Datasets and Phases now mirror each other. The empty Datasets tab shows Read patterns… and Simulate… (its toolbar used to appear only once a dataset existed, so the tab offered only a sentence and the demo link), as Phases always shows New phase…, Read structures (CIF)… and Simulate….
2. One name per action: Read patterns… in the File menu and the Datasets tab (was Read powder patterns… in File), Read structures (CIF)… in the File menu and the Phases tab (was Read a structure CIF… and From CIF / pdCIF…). New phase… is no longer in the Refine menu, which is about fitting; it stays in the Phases tab. Messages asking for a phase point to Phases instead of Refine.

## 2.12.0 — 23 October 2026

1. Dataset groups are removed. They only saved a fixed list of datasets for reselection, linked nothing, could not be edited or deleted, and looked like a second selection concept. Datasets are chosen with the selection alone: All, Shift+click ranges, checkboxes and the search box. Save group… is gone from the dataset toolbar, the scope menu offers the selection and all datasets, and projects, restore points and History restores no longer carry groups.

## 2.11.1 — 23 October 2026

1. Convert…: in the New space group list the standard setting of each of the 230 groups (standard, b-unique cell choice 1, origin choice 2, hexagonal axes: the settings ADDSYM names its results in) is in bold and ends in “· standard”; the closed list is bold while a standard setting is chosen. Typing “standard” in Find lists only them. Browsers that draw the list natively (Safari on macOS) show the label but not the bold.

## 2.11.0 — 23 October 2026

1. Wyckoff search, speed. Every wave of assignments cost restarts × iterations, and pruning acted only inside a wave, so an enumeration of up to 4000 assignments (10 per wave at 512 particles) could ask for 400 full waves. When the assignments need more than two waves, each is now screened first (10 % of the iterations, at least 60, one restart), re-scored on every reflection group, and only the best two waves’ worth get the full search, continuing from what the screening found. A simulated P-1 PbO₂ screens 155 assignments in 31 short waves and searches 10 in full.
2. Wyckoff search, equivalent assignments. Assignments related by an origin shift (quarters of the cell) or the inversion that maps the space group onto itself give the same intensities and distances and are now searched once: P-1 Pb₂O₂ goes from 477 to 78 assignments, Pnma PbSO₄ from 35 to 20, NaCl in P4/mmm from 12 to the 3 genuinely different placements.
3. Wyckoff search, scoring. The full-resolution re-score before ranking and after a Stop now covers every assignment of a wave, including those retired by the prune; they kept the score of the easier partial reflection set and could be ranked above full-resolution scores.
4. Wyckoff search, distance constraints. Up to 32 rules and 256 coordination slots (8 and 64 before). The kernel is compiled with the sizes each run needs, so a run within 8 rules and 64 slots pays nothing for the larger maxima. A cached kernel older than the page is refused instead of silently dropping the rules beyond its own size.
5. Wyckoff search, one source of truth. Its limits and defaults (rules, slots, sites per element, assignments, values of Z, density windows, contact, particles, iterations, restarts, screening) live in `js/wyckoff_limits.js`, read by the page, the worker and the kernel. The worker used 1000 iterations and 6 values of Z when the page sent none, against 2000 and 3 on the page, and accepted up to 24 values of Z against 12 on the page.
6. Wyckoff search, progress. The worker now forwards the live best structure, its assignment and its wR2 with each progress message (they were dropped, so a second Stop could not keep the running best). The bar covers screening, full search and every value of Z, and the wR2 shown is the residual rather than the penalised fitness.
7. ADDSYM after WPPF. A dataset fitted by Le Bail or WPPF offers its refined cell with its atoms (the Rietveld atoms when there are any, otherwise the atoms of the phase) besides its Rietveld model, so the search runs directly after a WPPF fit. The label no longer calls such a model a Rietveld model.
8. ADDSYM, occupancies and mixed sites. Atoms of one type whose occupancies differ by less than the new Occupancies within (default 0.02) are one kind of atom, in the search and in the conversion, which gives merged atoms their mean occupancy; refined occupancies of equivalent sites (0.987 and 0.991) no longer hide the higher symmetry. Atoms of different kinds on one point (a mixed site) are searched as one atom of their combined kind instead of being refused by the engine.
9. ADDSYM, responsiveness. The engine stays loaded in one worker between searches, the chosen tolerance is shown as soon as it is done while the sweep continues, an edit firing both input and change events searches once, and the timeout scales with the size of the cell. The former in-page symmetry finder, which only the tests still used, is removed; the Node regression now checks the Moyo engine the program runs, plus occupancy and mixed-site cases.
10. Opening a project clears every restore point and reads the project as saved: Undo no longer returns to the previous session. The confirmation says so.
11. Projects bring back the extracted intensities of the active method (Results reflection lists were empty until a refit), the values each dataset remembers for parameters it does not hold at the moment, and an absorption table loaded by hand. A Wyckoff result that is also a saved History record is stored once.
12. Saved Structure options are checked against the type of each option when a project opens; numbers typed in the form are kept (they were dropped on reload). The formula unit, Z and distance constraints belong to the project and are no longer kept by the browser between sessions.
13. Restoring a run from History keeps the Structure options (formula unit, Z, distance constraints); it reset them to the defaults.
14. Tests: Node checks for assignment equivalence, wave allocation, more than eight rules, the kernel markers, project intensities and remembered values, and opening a project without undo; `tests/wyckoff-search.html` runs the real GPU search end to end.

## 2.10.4 — 23 October 2026

1. ADDSYM calls the public Moyo WebAssembly API in a cancellable module worker and reports its returned group, standardized lattice, axes and origin. Engine errors and conversion restrictions are visible instead of being presented as no higher symmetry.
2. The active dataset’s fitted Rietveld model is now selected initially. Searches use its coordinates and cell together, including the saved Rietveld calculation while using WPPF or Le Bail. Previously the starting atoms were selected by default, and choosing a dataset could combine Rietveld coordinates with the WPPF cell.
3. Conversion keeps the chosen atomic source, previews adoption of that fitted model as the phase’s starting atoms and cell, and validates each dataset against its own Rietveld model. Stale starting atoms no longer veto a valid conversion of the selected fitted model. Undo restores the previous starting model and calculation banks.
4. A PbSO₄ browser regression supplies known Pnma coordinates as the fitted values of a 24-atom P1 phase, with an arbitrary origin and a separately distorted starting model. It checks detection, atomic-source changes, the saved Rietveld cell while using WPPF, conversion to five Pnma sites with Pb₄S₄O₁₆ content, undo, worker cancellation and engine errors. The six other crystal-system examples and existing conversion/project checks remain covered.

## 2.10.3 — 23 October 2026

1. ADDSYM’s Find higher symmetry… button uses the same blue primary style as Test the space groups. The dialog validates the submitted atomic source and tolerances before opening Convert…; pressing Enter before the delayed preview updated previously passed the old tolerance to conversion. Pending preview updates are cleared when the dialog closes.
2. Browser checks now exercise the first button click with the local WASM engine still unloaded, immediate submission after changing tolerance, phase selection independent of the active phase, and refusal to convert an already symmetric Pnma phase. Detection and conversion remain verified for Pnma and five other representative space groups.

## 2.10.2 — 23 October 2026

1. Charge flipping reports GPU preparation, shader loading and compilation, and the first calculation cycle instead of displaying a fixed 0 % during startup. Adapter/device requests and shader loading have 15-second timeouts; pipeline compilation and first-cycle validation have 30-second timeouts, followed by CPU fallback. Compilation is asynchronous. A failed GPU is bypassed for the remaining random starts of that search. Tests exercise stalled adapters, devices, shader transfers and compilation, verify the CPU fallback against the same seeded calculation, and check the running panel’s startup/cycle progress and Stop action.
2. The symmetry controls are visibly grouped under Commands → Structure → Space group: **Test · powder intensities** and **ADDSYM · atomic model**. Find higher symmetry… has moved out of the Phases toolbar into ADDSYM, with its own phase selector and no WPPF requirement. The Pnma dialog-to-conversion regression now uses this route.

## 2.10.1 — 23 October 2026

1. Find higher symmetry uses the locally bundled Moyo 0.21.0 WebAssembly engine (MIT license), including its standard-setting axes and origin shift. Atom mismatches are measured, and length and angle tolerances are checked independently. Browser regressions cover Pnma, Fm-3m, Fd-3m with an origin change, rhombohedral, hexagonal and monoclinic structures, and the full Pnma search-to-conversion workflow. Pmmm versus Pnma from powder intensities remains the systematic-absence test in Structure; a higher-symmetry search operates on the supplied atomic model.
2. Project loading clears the previous structure-search and extraction caches, restores saved fit mode, selected phase, profile defaults and search settings, and populates the selection before refreshing views. Acquisition wavelengths remain dataset properties across method changes; older projects use clean defaults for missing fields. Refreshing fit controls no longer overwrites the saved global-fit preference.
3. Chebyshev background coefficients are re-expressed when the fitted range changes, preserving the curve at the retained angles, including backgrounds restored from another method. Signed slope and curvature are checked against an independent polynomial with diffraction peaks and exclusions in Rietveld, Le Bail and WPPF.
4. Method changes preserve cached plots of unchanged calculations. Repeated inspection of an immutable saved fit also reuses its evaluated patterns instead of solving its intensities again on each UI refresh; project loading clears these caches.

## 2.10.0 — 23 October 2026

1. Phases → **Find higher symmetry…** looks for symmetry a structure has but its space group does not use, in the manner of ADDSYM in PLATON (after Le Page's MISSYM), and hands the result to Convert…. It works on the starting model or on the refined positions of any dataset holding the phase, with a distance tolerance for the atoms (0.2 Å by default) and a tolerance for the cell (1 % and 1°).
   - The structure is expanded to the full cell; lattice translations that map every atom onto one of the same kind give the true primitive cell (extra centring, or a smaller cell); the rotations its Delaunay-reduced lattice allows within the cell tolerance are tested for a translation that maps all atoms onto atoms of the same kind; the group they form is named in the standard setting (standard, b-unique cell choice 1, origin choice 2, hexagonal axes for R groups), with the new axes and origin.
   - The report gives the cell metric, the lattice points per cell, the group found and whether it is higher than the present one, the new cell, how the sites merge and how far atoms must move, the operations the structure has and the present group does not use (with the largest miss of an atom), and the group found at 0.05, 0.1, 0.2, 0.3 and 0.5 Å.
   - Convert… opens the conversion already set to that group and transformation; the conversion merges the atoms and converts every dataset, as before.
   - Checked on NaCl, Si (Fd-3m origin 2), CsCl, W, spinel, wurtzite, Mg, Bi₂Te₃ (R-3m), rutile, anatase, P2₁/c, C2/c, Pnma, P2₁2₁2₁ and P-1 structures written in P1: each is named correctly, in well under a second.
2. Convert…: the tolerance is now how far an atom may move to take the new symmetry (the distance to the symmetric average), as in the new search; before, two equivalent atoms each moved by up to the tolerance could be refused. Atoms merged from the pieces of one split atom get its name back (Na1a … Na1d → Na1).

## 2.9.2 — 23 October 2026

1. Convert…: the new space group is chosen from a drop-down list of all 520 settings of the 230 groups (number · symbol · crystal system · setting), with a Find box above it that keeps the matches as you type a number or a symbol and selects the setting the text names (14 → P121/c1, P21/n → P121/n1, Pnnn:2). Enter in Find accepts the match instead of starting the conversion; a Find with no match is refused. The previous field showed a drop-down arrow that opened an empty list.
2. The space-group suggestions of the Phases field and of New phase list every setting, written as the fields write them (Fm-3m, P121/n1), labelled with number, crystal system and setting. They used the spaced symbols of the 230 standard settings only ("F m -3 m"), so the list stayed empty for a field holding "Fm-3m" and other settings could not be picked.
3. Typed space-group symbols resolve to the right setting. The exact symbol of every setting now gives that setting (origin choice 2 of 30 groups, such as Pnnn:2, used to give origin choice 1); short monoclinic symbols give the standard b-unique setting (P 21/c → P121/c1, it gave P121/a1; P21/n, which was not recognised, → P121/n1); and a monoclinic number gives the standard setting (14 → P121/c1).

## 2.9.1 — 23 October 2026

1. Phases: the space-group row now uses the same columns as the phase-name row, so the space-group field lines up with the phase name, Convert… sits under the colour selection and Browse… under Edit, all at the same size. Browse… no longer wraps onto a line of its own.

## 2.9.0 — 23 October 2026

1. One running panel for every calculation (fits, extraction, space-group test, charge flipping, Wyckoff search), at the top centre under the header instead of a small card in the bottom-right corner. It shows what is running, its progress (the same as the progress bars of the footer and of Commands → Structure, which it now mirrors) with the elapsed time, a progress bar, and the only Stop of the page: a red ■ Stop button that also names its key, Esc.
2. The formula unit and Z rows say what each method does with them, instead of the same sentence twice. Charge flipping: the formula is optional and only names the peaks (count × Z atoms per cell, strongest scatterer on the highest peaks); Z = Auto comes from the highest peak. Wyckoff search: the formula is required and is exactly what is placed; Z = Auto tries every Z with a plausible density.

## 2.8.0 — 23 October 2026

1. Phases → **Convert…** (left of Browse…) describes a phase in another space group or setting. The structure is expanded to the full cell, carried to the new axes and origin, and reduced with the new symmetry; the cell, the atomic positions, B and occupancies of the starting model, of every dataset holding the phase (each from its own refined values) and of their saved calculations are converted, with their fit flags. The transformation (new axes a′, b′, c′ and origin) is found automatically among axis changes with entries −1, 0, 1 and origin shifts in eighths, or entered by hand (e.g. "a+b,-a+b,c", "1/8,1/8,1/8"). A live preview shows how the groups relate (same group in another setting, subgroup, supergroup), the old and new cells, the sites that split or merge, and the cell content.
   - A subgroup splits sites (Fe1 → Fe1a, Fe1b); a supergroup merges atoms the new symmetry relates, and is refused, with the atom and distance named, when the structure or any dataset's refined positions lack that symmetry within the tolerance (0.1 Å by default).
   - The preferred-orientation direction and uniaxial broadening axes follow the new axes; anisotropic size and Stephens strain coefficients are flagged for refinement; atomic constraints and parameter links of the old atoms are removed and counted. Fit results are cleared; Ctrl+Z undoes the conversion.
2. Projects are saved with the extension **.project**. Opening accepts .project, .archive, the .powder6 files of earlier versions, and any zip that holds a project.json, whatever its name; other zips still go to the pattern readers.

## 2.7.1 — 23 October 2026

1. Saving a project always ends with a message and, unless cancelled, a file. After the options, Choose file… opens the browser's Save As dialog before compression, so the name and folder are chosen while the click still counts; the compressed project is then written there. Where the browser has no Save As (or refuses it), the project downloads to its download folder and the message gives the file name and where to look if the browser held the download. Saving while a calculation runs, with nothing to save, a cancel, and a failure while compressing or writing each give a message instead of nothing. Download links stay valid long enough for large files.

## 2.7.0 — 22 October 2026

1. Charge flipping accepts up to 128 random starts (adaptive mode 6–128, manual 1–128). Adaptive mode keeps only the twelve lowest-R density maps for the map-agreement check, so a large budget does not hold every map in memory.
2. A stopped Wyckoff search keeps its solution. The worker reports each finished value of Z as soon as it is refined, and the page keeps the live best structure of the Z still running. A second Stop, a worker crash or an error after a stop now keeps what was already received instead of discarding it; such a result is labelled, and a structure taken from the live search is marked as not refined. A new CF or Wyckoff result also resets the result selector to the latest solution.
3. The Wyckoff worker's list of solutions per Z now carries `ranked` and `obsPerParam`, so the “Unranked” caution appears for those solutions too.
4. History lists all the information of the chosen run: run settings and refinement options, global summary, phases, limits and shared parameters, and for each dataset its statistics, phase R factors, warnings, every parameter with its e.s.d. and refinement flag, and the instrument and background. Charge-flipping and Wyckoff records list their settings, solutions, sites, random starts and search log.
5. History can be saved: Save History writes every record with its results and observations as JSON; Save run report and Save report of all runs write the same information as text. Both use the Save As dialog where the browser has one, and fall back to a download when it refuses. History is read back only as part of a project.
6. Set on a charge-flipping or Wyckoff record restores the intensities the solution was made from (it wrote a field nothing read). If its phase or dataset is gone, the solution is still shown and a warning says the intensities could not be restored.
7. Charge-flipping and Wyckoff records have their own pruning quotas (the History count setting applies to each), so structure searches no longer push WPPF fits out of History. Pruning and the “working setup differs” check no longer re-serialize every record on each update.
8. Deleting a History run asks first, and says so when the run is kept; Ctrl+Z restores it.
9. After Stop, the Wyckoff search refines its best structure before returning it. A toast, the progress bar and the busy card ask the user to wait while it does; a second Stop still ends at once with the unrefined search positions.
10. Opening a project checks its History record by record: unknown kinds, duplicate ids and missing models are rejected; runs whose observations are not in the project are left out and named in the Log instead of failing later at Set; the record counter is repaired so new runs never reuse a saved id.
11. index.html now holds the complete layout (Commands and Results panels, result tabs, History, Structure results). The start-up code that rebuilt the page from an older layout is gone, so the markup is what you see. There is a single About control, and the PowderV2 reference appears once.
12. Accessibility: the File/Data/Refine buttons form a labelled group of menu buttons instead of an incomplete menubar; the space-group dialog hides its axis-choice row with the `hidden` attribute instead of inline styles, and its search fields have labels.
13. Scripts load deferred from the head in their dependency order. Start-up checks that every module is present and, if one is not, names it on the page instead of failing on an undefined value.
14. `ui.saveTextFile` is generic (title, file type and remembered folder are options); the instrument-resolution export passes its own.
15. Comments that named powder5.html as the host page now name index.html and rv_solve.js.
16. The plot keeps its zoom when the model changes: a new space group, cell, phase, method or refit redraws the curves in the region being inspected. It rescales only when what is plotted changes (the datasets shown, their observations, the intensity scale, background subtraction or the view mode), or on Autoscale / double-click.
17. Method lists what the fit will refine, grouped (scales, background terms, zero and geometry, cell, sample profile, resolution, preferred orientation, atomic positions, B and occupancies per phase, and the reflection intensities of WPPF and Le Bail phases), instead of only a count.
18. A WPPF fit with nothing ticked is allowed: the reflection intensities are variables of their own and are refined at the current cell and profile. Rietveld and Le Bail still need a ticked parameter.
19. Charge flipping places every element of the formula it can. A heavy atom needing fewer atoms per cell than its peak's site holds (for example 2 Fe on a peak that landed slightly off a 2-fold inversion centre) has the peak moved onto the nearest free special position of small enough multiplicity, up to 0.6 Å away; the move is shown in the sites table. Elements that still cannot be placed are named in the toast and under the sites table instead of being silently left out.
20. A Wyckoff composition blocked by a stated coordination number now says so. A constraint such as “Fe C 1 1.2/1.8” gives Fe a coordination of 1; an odd coordination cannot sit on an inversion centre, which can leave Fe no position. The error names the constraint, the excluded positions and the syntax for a distance window alone (“Fe C - 1.2/1.8”), instead of advising to raise the site caps; the constraint editor warns about odd coordination numbers as they are typed.
21. A Wyckoff failure for a single value of Z is written to the Log once, as the error, instead of twice.

## 2.6 — 21 October 2026

1. Restored phase-scale and constant-background estimation by removing a call to an obsolete model method. Estimation also clears results that no longer describe the current values.
2. Preserved supplied uncertainties in GSAS ESD/FXYE and XYE imports. Sorting, filtering and duplicate removal keep uncertainty and weight columns aligned. pdCIF weights, including zero-weight exclusions, survive project saves, undo and exports.
3. Invalidated fit statistics, parameter uncertainties and extracted intensities when phases are added or deleted, including results stored for other calculation methods.
4. Kept pdCIF metadata within its data block. Files containing several profiles import each profile separately, retaining its wavelength and referenced phase assignments.
5. Preserved neutron radiation on pdCIF import. Neutron and explicitly single-wavelength files no longer acquire an assumed X-ray doublet.
6. Shared CIF tokenization now handles inline comments, quoted values, wrapped loop rows, scalar values on following lines and semicolon text fields. Incomplete rows produce an error instead of silently dropping atoms.
7. Blocked Rietveld calculations when required scattering factors are missing, both before dispatch and inside the fit core. Valid zero and negative neutron scattering lengths remain supported; Le Bail and WPPF do not require atomic scattering tables.
8. Included radiation type, both doublet wavelengths and their intensity ratio, and the zero correction in pdCIF exports. Imported weights are also respected by GSAS-II exports; points with an imported zero weight are omitted from XYE output.
9. Restored weighting and calculation defaults with undo, together with the saved refinement state, and persisted the restored settings.
10. Added automatic WebGPU parallel tempering for Rietveld, Le Bail and WPPF, including pattern evaluation, intensity solves and replica exchange. Trial costs are validated against the CPU model; GPU failures restart CPU PT. Final LM refinement and uncertainties remain double precision. Results record the backend and fallback reason.
11. Added right-drag background anchors, exact cursor placement in angle and intensity, a yellow guide while editing, and distinct fixed/refinable markers. Split Solve's Sample and Resolution refinement controls. Le Bail/WPPF atom displays and structure exports now use the Rietveld atomic model; method-specific backgrounds and fitted results are preserved.
12. Gave refinable background anchors a dedicated magenta colour in both themes, independent of dataset colours. Fixed anchors remain hollow grey and the active editing guide remains yellow.
13. Split the workspace into independently navigable Commands and Results panels, using Powder5 as a layout reference while retaining Rietveld. Commands contains Datasets, Phases, Method, Structure and Settings. Results contains Plots, Le Bail, WPPF, Rietveld, Structure, Log and History. Each results view shows one selected run; inspecting/exporting previous fits leaves the working setup untouched, with explicit Use as start/Set restoration. Structure inputs and outputs are separate. Panels can be resized and swapped, with the order remembered. Coloured dataset tabs remain the sole editors of dataset values and refinement flags.
14. Added named dataset groups, focused inspection and an observation overview for large selections. FIT uses the selected datasets and their current values for the active method. Conflicting shared starting values in global fits require an explicit dataset value or custom value. Plot controls independently toggle anchors, background, phases, reflections and background subtraction.
15. Added persistent immutable calculation checkpoints, grouped batch/global restoration, Keep, count/byte budgets, protected current results and structure-solution provenance. Setting an older fit makes it the method's current result.
16. Added explicit dataset targets for resolution and sample imports, and phase/assignment targets for structure transfers. Resolution function types now belong to datasets, including in CPU and WebGPU calculations. Exact parameter links can connect phases and datasets and eliminate dependent variables.
17. Added a dedicated About action left of Panels and made the application title static. Phase renaming uses Edit beside the colour picker; phase removal is available on each phase row. Removed redundant Method/Structure headings, moved dataset deletion beside Save group and exclusions after Background, and replaced the resolution-function selector with calibration Load/Save actions and automatic profile detection.
18. Widened the divider and added a visible resize grip. Exclusions use the standard dataset group header. Absorption data loads automatically without a toolbar button. Copy controls identify their source and parameter/flag scope and hide for a single dataset. Instrument profiles are selected only in Datasets, with TCH as the default and independent sample size/strain for all available families. Removed the Next calculation inspector, Method navigation shortcuts and History heading; FIT follows the selected command method.
19. Flattened Method setup and CF/Wyckoff settings, putting concise instructions and prerequisite warnings in the FIT block. Renamed the space-group count to Number of reflections, defaulted it to the available intensities (maximum 600), and added strict integer/range validation; changing it rebuilds the precision block used by the test. Kept runs now carry a visible marker in selectors and History cards, with Set versus Keep explained in the interface and documentation.
20. Simplified empty views: hide the phase chooser without phases, show only the loading hint and demo link without datasets, and hide Method setup until both exist. Documented that successive fits start from each dataset's latest working values.
21. Greyed out Anchors when the plotted view cannot display spline anchors, retaining its saved preference. Replaced CF formula naming with a checkbox applied when copying atoms; selected sites, manual element types, cancellation and archived results are preserved.
22. Added optional CF adaptation with a data assessment and parameter-plan preview: raw I/σ and resolution shells, fitted-width overlap grouping shared by CPU/GPU, three settings across 6–12 starts, paired independent seeds and map comparisons allowing periodic translations and inversion. Search parameters, seeds, errors and correlations are retained in History and reports. Manual settings remain available, no extra intensity cutoff is applied, and stopping preserves the best completed map. Fixed P1 site extraction to keep its unconstrained origin. The parameter rules are documented as heuristics with controlled numerical and workflow validation.

23. Added profile-conditioning diagnostics: negative instrument Gaussian variance over the fitted range, locally dependent parameter combinations and zero-effect variables. Results and dataset statistics retain the reasons in reports, History and projects. Missing uncertainties are labelled as unavailable rather than declaring every affected parameter unconstrained. Fixed numerical cancellation in the negative-variance width continuation on CPU and WebGPU; refinement flags and fitted coefficients are preserved.

The application and fit core report version **2.6**. Projects now use format 3 in a compressed `.powder6` archive, with binary observations stored once and persistent calculation history.

Run the regression checks with:

```sh
node --test tests/regressions.test.cjs
```
