The engineering contract, stage by stage
The demonstration above is the pipeline's meaning; the contract below is its law — every normative rule. Collapsed because it is reference, not reading.
1 · Qualification — fail-closed, before any reduction
Not yet implemented: this stage. The counts fit checks only the form of its inputs, such as one whole, non-negative count per time bin in each run. It multiplies each run’s predicted counts by the live fractions it is given, one per bin in (0, 1], taken as exact. A corrupt or truncated run fails before it can meet a valid open beam: pulse IDs, live time, proton charge and beam monitors, chopper state, moderator condition, detector HV/thresholds, geometry, trigger and timing epochs, run completeness, sample motion, frame overlap, metadata consistency are all checked here. Dead time, pile-up, gain depletion and nonlinearity are corrected using the detector-health characterization, with propagated uncertainty, and bounded by a hard rate-validity limit — sample and open rates differ, so these effects never cancel in a ratio, and uncorrected losses invalidate the Poisson likelihood itself. The beam-borne background is a term of the forward model (stage 3), fitted with the sample run’s counts: it passes through the pulse and scales with the normalization, and black-resonance floors, of the sample or of a notch filter in the beam, pin it. Counts that bypass the pulse, such as gammas and room background, get a term of their own when a case needs one, constrained by dedicated runs such as blocked-beam runs. The detector-health mask comes from independent diagnostics — hot, noisy, timing-shifted, cross-talk and saturated pixels — never from the science counts being fitted, and never a low-count screen. Not yet in the code: the old fitting path masks the pixels its caller gives, and the GUI gives the dead pixels the input file declares joined with those each run’s own counts flag — a pixel with no counts is dead, a median-deviation screen finds hot ones — over the sample and open-beam runs; the counts fit takes no mask.
2 · Reduction — one convention, native TOF preserved
Not yet implemented for the counts fit: this stage and its mask; its caller gives each run’s counts per time bin. Reduction hard-excludes only the sample ∪ open-beam unhealthy-pixel union (masking by counts would bias the Poisson statistics it feeds). Native-TOF bin edges, the same for both runs, are never re-binned downstream; per-bin width Δt is carried. Monitor counts as observations with uncertainties are not yet implemented: the proton-charge ratio c_q enters as an exact factor. The live fractions enter as exact factors; their counting noise is second order in the hits per pixel per shutter in a bin. Only the product c_q·a enters the sample counts, so a fitted normalization a absorbs any error in c_q. Reduction never rebins to energy: E(t; L, t₀) is evaluated inside every likelihood evaluation at the current calibration parameters — that is what lets L and t₀ float with their covariance; a baked axis would silently pin them and re-interpolate counts. A derived energy axis is a display product of stage 5 only. No per-pixel geometric L (≈6×10⁻⁷ centre, 3×10⁻⁵ corner — orders below any stated budget); per-pixel t₀ only from independent timing calibration. The domain decision lives here: counts is the canonical arm; transmission T=(S/Q_s)/(O/Q_o) is a community-convention diagnostic formed only if every validity test passes (open-count bias, black cores, shared-open-beam covariance, background and monitor uncertainty, and the forward-simulated resolution-order bound) — never the canonical fit domain. Not yet implemented: the validity tests. The counts fit forms no transmission. The old fitting path, on transmission or on counts without a resolution, has been deleted; the counts fit is the only fitting path in the code. The output carries the provenance block — the Data tab’s five groups as known at reduction, later-registered conditioning identities extending the block per the Data-tab rule — including bin edges, masks, live-time and monitor observations, calibration-posterior identity, nuclear library/version, component versions, configuration hashes and seeds; background and calibrant runs reduce through this same path. Not yet implemented: the provenance block. A counts fit carries none; the pulse calibration file records its foil, the foil’s stated densities and temperature, the library its isotopes were read from, and its runs (stage 4).
3 · Forward model + likelihood — one invocation
σ(E; T_eff) is assembled per isotope with the evaluation's declared resolved-resonance formalism (ENDF File 2: RM / MLBW / SLBW / RML with KRM = 3 as given — never an assumed Reich-Moore; an evaluation declaring a formalism outside the supported set, e.g. RML with a fission channel, is rejected fail-closed, never silently substituted), the full parameter set, File-3 background where present, boundary rules honoured; isotope contributions sum in the exponent; Doppler broadening at T_eff with the lattice-model family declared. Nuclear covariance is carried under an explicit failure policy: availability checked, non-PSD refused, missing covariance → declared default or rejection, one shared uncertainty across all fits, model discrepancy its own term. An evaluation whose resonance energies disagree with measured transmission in a window is used with that window left out: excluded_windows_ev gives 13.6–14.2 eV for ENDF/B-VIII.1 Ta-181 and nothing for any other library or isotope; a material names its library, and the counts fit and maps leave out of the deviance and the information the sample run’s bins overlapping the span between the mean arrival times of a window’s two ends at the fitted t₀, flight path and pulse, held like every bin to predictions of zero or more; the resonance stays in the model at the evaluation’s energy, and its wings and the pulse carry part of the window’s counts outside it, where at high counts per bin they raise the sample run’s overdispersion; a calibration records the library, and its line span holds the lines in those windows like any other. Not yet in the code: the old fitting path applies no window; the counts fit carries the File 32 covariance its caller gives. The kernel K(t|E) is the Ikeda–Carpenter pulse with α = α₀√E + α₁, β = β₀√E and R constant or linear in √E up to R_high, folded with a triangle of FWHM h for the proton pulse and the other constant-time widths, and, with a detector tail, recorded late by an exponential delay of mean τ_D for a fraction f of the counts (the code also has a constant term β₁ in β). It acts on each run’s expected counts (Φ·ε·T) and is anchored at emission: a neutron of flight time u arrives at t₀ + u plus a delay drawn from the pulse, so t₀ is a clock offset, L a path length, and the pulse’s mean delay moves the lines. Bin k counts O_k = ℓ^O_k·[Σ_i w·φ_i·P_ki + p·G_k] in the open beam and S_k = ℓ^S_k·c_q·a·[Σ_i w·φ_i·[T_i + b(E_i)]·P_ki + γ·p·G_k] behind the sample, with φ_i the beam at grid point i, w the grid step, P_ki the chance that a neutron of point i arrives in bin k, ℓ the live fractions, c_q the proton-charge ratio, a the normalization, G_k the time background’s counts per pixel in bin k, p the region’s pixels and γ its gamma transmission. The background b(E) = b₀ + b₁/√E + b₂·√E is beam neutrons that reach the detector another way, so it passes through the pulse and scales with a; counts that follow the proton charge but bypass the pulse, such as prompt gammas, are the time background G, whose C, A and τ the counts fit holds known, fits or takes measured, and the map does not carry. Every other non-Beer-Lambert contribution (container attenuation, multiple scattering, PSF mixing) is modelled, bounded with a stated magnitude, or measured. In the code, single scatter-in is its own term, and the counts fit spreads a share h of the counts arriving in each detector cell over the regions by a radial exponential kernel, region r recording (1 − h)·μ_r + h·Σ_q F_rq·μ_q. Not yet in the code: container attenuation and multiple scattering are neither modelled nor bounded, and the map carries no spread. Objectives: Poisson/KL deviance with a calibrated GOF reference (D/(n−k)→1 only asymptotically; per-bin E[D] ≈ 1.15 at λ=1); the transmission diagnostic uses Pearson-weighted Gaussian χ², never Neyman. Not yet in the code: no transmission diagnostic is formed. The old fitting path, the only one Python, the GUI and MCP reach, either forms T = (S/O)·(Q_o/Q_s) with an exact proton-charge ratio and no validity test and fits it by least squares weighted with σ from the measured counts, a Neyman χ², or fits the two runs’ counts by a joint Poisson deviance without a resolution. The identifiability screen is layered — design time, per configuration, per pixel class on the actual data, post-fit — fails loudly, and never converts non-identifiability into a hard pin: pinning is permitted only under the marginalization criterion. The counts objective is each run’s half Poisson deviance divided by that run’s overdispersion, plus ½((x − x_m)/sd)² for each quantity measured elsewhere as x_m ± sd, plus ½(θ − θ_C)ᵀC⁻¹(θ − θ_C) over the calibrated pulse numbers θ, with θ_C and C from the calibration. A run’s overdispersion is the variance of its counts over their Poisson variance, estimated from its Pearson residuals and at least 1. Not yet in the code: the calibrated GOF reference, the layered screen and the criterion; the counts fit holds a quantity given as known exact.
4 · Fit instances — four prior patterns, one engine
Calibration is the experiment fit with the roles swapped: it fits the open-beam and sample runs of a foil chosen for isolated resonances spanning the band at a range of optical depths, or of several foils or thicknesses in one fit, each with its own t₀, L and overdispersion; the foils’ areal densities and effective temperatures are measured and enter as Gaussian priors with their stated uncertainties. It reduces through the shared axis-free path, starts the fit at the surveyed L and nominal t₀, predicts σ(E; T_eff) with ENDF covariance carried, and jointly fits {L, t₀, θ_res} with the beam, normalization and background against modelled dip shapes, the kernel anchored at emission — never centroids, never a sequential position/width split. It emits the fitted θ_res as (θ̂, Σ_cal) with off-diagonals, without their bounds and marginal over everything else — or samples where non-Gaussian — plus the kernel form and its anchor, the span of resonances it was fitted on, and its full conditioning set: the foils’ stated values and run identifiers, the nuclear library and the configuration; L and t₀ go out only as starting values, since each experiment fits its own. Not yet in the code: ENDF covariance, samples for a non-Gaussian posterior, the configuration in the conditioning set, and several foils or thicknesses in one fit. Transfer is enforced by a compatibility gate (configuration hashes: moderator condition, thresholds/HV, rate regime, chopper, geometry, epoch; drift bounded by bracketing references and control charts; on mismatch reject or attach an explicit drift model), and validated by holdout — held-out resonances, thicknesses or repeat runs are predicted, not fitted. Not yet implemented: the gate and the holdout. The code checks transfer between foils: a physically different foil, calibrated alone, must give the same pulse — d² = dᵀ(C_a + C_b)⁻¹d, with d the difference of the two calibrations’ means over the numbers both fitted, against χ², with p above 0.01 — or record_transfer refuses the calibration; with no second foil the file records the transfer as unchecked. Not yet in the code: a calibration written without record_transfer also reads unchecked when a transfer test it failed was run. An experiment refuses a sample with a line in its window outside the calibration’s line span, and reports whether its counts accept the calibrated pulse.
Density frees (n·d)ᵢ + nuisances with T under a prior (pinned only by the marginalization criterion; τ₀ ≈ 2.2 is the idealized thickness optimum). Temperature frees T_eff with n·d under a prior; resonance sets are ranked by expected information after marginalization; the lattice-model family is declared and its uncertainty propagated. In-situ declares its sharing structure as part of the experiment definition — global reference n·d₀ under the integrated expansion constraint n·dⱼ = n·d₀·exp(−2∫α(T)dT), per-frame T, and the time-dependent instrument and beam terms (a global fit does not protect against drift it does not model) — then fits the series jointly. Every experiment instance also declares its spatial estimator (independent per-pixel → binning → regularization → joint inversion) and ROI geometry as part of its definition. In the code, density, temperature or both are one fit of one open-beam and sample pair in one or more regions, each with its own beam, background and material or none, sharing the normalization: each quantity is fitted, known, or measured (a Gaussian prior); t₀ and L are fitted to the pair, starting at the calibrated values; the calibrated pulse numbers are fitted under the file’s correlated prior. The binning rung of the spatial estimators is fit_map. Not yet implemented: the marginalization criterion, ranking resonance sets, the lattice model’s family uncertainty, in-situ series (several pairs in one fit) and the other spatial estimators.
5 · Results / QC — every instance terminates here
The product family: value map, uncertainty map (total marginal covariance authoritative — not yet in the code: the counts fit’s covariance takes each known quantity as exact and is conditional on any quantity that ended on a bound being held there; the statistical/systematic split is a documented decomposition convention; credible intervals where posteriors are bounded or skewed), calibrated GOF/deviance map, trust mask, and residual cube in signed-deviance / randomized-quantile form. Derived display products — the energy axis at the fit’s own t₀ and L and the transmission spectrum — are produced here for display and cross-checks only, never the fit domain. Consistency tests each carry a predicted value: 1D↔2D = the uniform fit of the counts the 2D field predicts (not the 2D mean); transmission↔counts within ratio-bias + resolution-order bias; deviance against its calibrated reference; per-resonance residuals per line. Nuisance flexibility is restricted so unexplained structure cannot be absorbed. Every failure class has a predefined outcome — fail-closed or a declared degraded mode: missing open beam / background / monitor data, partial frames, dead-time violation, calibration incompatibility, missing or non-PSD covariance, kernel extrapolation, counts that bypass the pulse (gammas, room background), non-identifiability, non-convergence. In the code one counts fit returns its values and covariance, the deviance, each region’s predicted counts and overdispersion for both runs in every bin, the pulls of the measured quantities and the pulse-consistency test. It refuses malformed counts or live fractions, a sample line outside the calibrated line span, a window that neutrons from outside the pulse’s energy span can reach, a cross section read outside one evaluated resolved range, and a bin it predicts negative, or empty while counts were recorded. A fit that does not converge returns no covariance; a quantity on a bound or undetermined gets NaN error bars, and the other entries are conditional on the quantities held on their bounds and take known ones as exact; disagreement with the calibrated pulse is reported, not refused. fit_map returns these per patch, and the map it returns gives the residuals in signed-deviance form one patch row at a time. Not yet implemented: residual blocks written out stage-then-commit, randomized-quantile residuals, calibrated GOF reference, display products, the consistency tests above, and the failure classes for partial frames, dead time and missing monitor or background data.