IMPLEMENTATION AUDIT Prepared from the six current uploaded notebooks and tsunami-implementation-only.tar.gz Corrected build: 2026-09-21-r10 Actual-device r2, r3 and r4 follow-up The first saved browser report passed 239 of 240 stage checks. The only failed checkpoint was overlap_nonlinear rhs3 eta. Its maximum absolute discrepancy was 2.9802322387695312e-8 and its relative L2 discrepancy was 5.9592755242583454e-8. This is float32-rounding scale, but it correctly failed the unchanged checkpoint tolerance. Build r3 added a depth_flux pass before every RHS pass and made the continuity RHS differentiate that stored buffer. The r3 device report nevertheless reproduced the same 239 of 240 result, maximum discrepancy and relative L2 error. Its added diagnostics identified the first tolerance violation at flat index 173: actual 0.00011604465544223785, reference 0.00011603906750679016, allowed difference 5.481172025203705e-9, and error/tolerance 1.0194782104991857. Build r4 split dt*rhs, stage addition, base weighting, stage weighting and final addition into separate storage-buffer dispatches. Its actual-device report was numerically identical to r3 at every recorded checkpoint, including the same failing value, maximum discrepancy and relative L2 error. This ruled out SSPRK3 expression contraction as the cause. Build r5 added separate continuity storage passes, but its device report remained identical to r3 and r4. Build r6 then corrected the checkpoint topology by supplying the exact Python stage input to each isolated RHS test while independently checking the complete propagated path. The supplied r6 browser screenshot reported PASS for all 247 device checks. Builds r7 and r8 preserve that solver and its unchanged tolerances while restoring the location-based ETOPO1 workflow and preventing a distant-gauge run from using the former two-hour default. Scope and evidence The supplied archive was inspected directly. Its three JavaScript modules, reference generator and parity fixture were compared with numerical functions extracted from the current notebook uploads. The six notebook files in this delivery have the same SHA-256 hashes as those uploads. No complete production input arrays, NOAA observation file or live-site HTML were supplied. Consequently, the fixes address the uploaded implementation; they do not prove which single fault caused a previously displayed live-site zero waveform, and they are not a live-site deployment. Independent r7 local checks comprise 251 numerical/reference checks, 35 data interoperability checks and 45 host layout/scheduling checks. All 331 passed. The numerical checks observed zero maximum absolute discrepancy in the checked JavaScript-versus-NumPy arrays. The prior r6 offline DOM report is retained as historical evidence; the r7 DOM suite was updated for online loading but was not rerun because Playwright is unavailable in this preparation environment. The delivered app still requires its normal device test before use. Shader validity and false parity success The original webgpu/tsunami-webgpu-port.js calls isNan and isInf in its clean function and validity reduction. Those calls are not WGSL built-ins. The corrected shaders use IEEE exponent-bit classification, and shader compilation messages and device validation/loss errors are surfaced. GPU failure cannot be represented as a successful run. The original tsunami-python-port.js compareArrays at line 573 computes Math.abs(actual-expected) without rejecting NaN. Comparisons with that NaN do not make the pass flag false. A NaN input could therefore receive a PASS. The replacement rejects missing, mismatched, empty and non-finite arrays, invalid tolerances and entirely erased nonzero reference signals. A missing required checkpoint is an error rather than a skipped comparison. This fault was reproduced and covered by regression tests. The original uploaded GPU module already separates its dispatch calls into compute passes. This delivery preserves that arrangement and checks buffer dependencies. It does not claim that adding pass boundaries alone fixes the uploaded archive or establishes the cause of the earlier live-site run. Bathymetry and array identity The original controller's loadGrid fetches an ERDDAP etopo1_bedrock subset and derives a stride from a requested target grid size. Its own interface notes that this is not the saved Python bathymetry. It cannot reproduce a run that used different saved bathymetry simply because both datasets represent the same ocean. The saved Notebook 1 output reports nx=2400, ny=3000 over the Sumatra-region domain, with signed bathymetric values. No corresponding native array file was uploaded. The corrected workflow reads the real file or an exact-array export, preserves coordinates and dimensions, and never inserts a replacement online ocean. Source interpolation follows Notebook 3. Longitude aliases, transposed arrays, classic NetCDF offsets, packed scale/offset metadata, missing-value rejection and float64 source interpolation before float32 storage are tested against Python-generated fixtures. Direct NetCDF4/HDF5 reading is not implemented in JavaScript; those files have an explicit Python conversion route, not a silent fallback. Source formulas and loading priority The source functions in the notebooks are not interchangeable implementations of one identical model. Notebook 1 creates a rectangular uplift/subsidence pattern and applies two passes of axis-wise, 11-tap Gaussian convolution with zero padding. Its default uplift/subsidence levels are 0.8 and -0.6 times slip. Its dip, rake and depth entries do not participate in that source calculation. Notebook 2's okada_displacement uses its supplied rotated coordinates, trigonometric expression and exponential tapers. Its geographic conversion uses 111000 metres per degree and the source latitude cosine, unlike Notebook 1's Earth-radius conversion. Poisson ratio is not used in its returned displacement. This delivery preserves that function but does not upgrade its name into a claim that it implements the complete analytical Okada solution. Notebook 3's generated fallback is another source: elliptical regions, overlapping assignment order and SciPy Gaussian filtering with reflected boundaries. Its default slip is different again. The corrected implementation preserves that fallback only when it is explicitly chosen. Notebook 3 loads a saved sumatra_okada_initial source ahead of an okada_eta source. Its saved run uses the Notebook 1 path, not necessarily the file most recently written by Notebook 2. The old website always generated the Notebook 1 source from its source-generation action even while exposing other fault controls. The replacement distinguishes all three modes and an imported-source mode, labels inactive parameters, and records the selected mode. Choosing Imported eta0 is the clearest way to reproduce the exact source actually used by a previous Python run. Numerical state and operator semantics Notebook 3 explicitly uses float32 device arrays. It is not a double-precision reference solver. Its eta, u and v have the same two-dimensional shape and its derivatives are collocated centred differences, with one-sided boundary derivatives. The filename does not establish a staggered C-grid implementation. Replacing it with a different staggered solver would be a method change, not a faithful port. The corrected JavaScript reference explicitly reproduces float32 operation ordering, nonlinear momentum grouping and scalar conversion. GPU arithmetic is checked with stated absolute/relative tolerances to account for device evaluation differences. Derivatives, total depth, momentum fluxes, each RHS, each raw RK stage, each sponge result and each post-boundary result are compared, rather than checking only a final colour map. The notebook computes H0=max(-z,H_MIN), including positive-elevation land. It then uses max(H0+eta,H_MIN) in the continuity fluxes. This behaviour is preserved for implementation reproduction. No wet/dry coastline mask has been inserted, and the interface warns that it is not an inundation model. Sponge and boundary order Notebook 3 applies the sponge at every RK stage, then copies elevation boundary rows and columns, and zeros velocity boundaries. The order matters at corners. Its horizontal sponge loop overwrites prior x assignments when sponge layers overlap, while the vertical loop uses minimum factors. A nearest-edge shortcut does not reproduce those overlapping-width cases. The corrected GPU factor follows the sequential overwrite/minimum behaviour; the regression suite includes an overlapping 20-cell sponge on a 28 by 26 grid, nonzero velocities, nonlinear momentum and a no-sponge case. The three RK stages retain the original state separately, do not alias writable output with a read buffer, materialize depth and flux arrays before each RHS, materialize flux differences and derivatives, materialize every float32 SSPRK3 subexpression, and perform boundary handling after each stage. Host tests verify the twenty-seven-dispatch order and parameter-buffer offsets. These host checks are not substitutes for GPU execution, so the delivered device suite also compares the resulting arrays. Time advancement and gauge records Adaptive CFL logic retains the supplied gravity, minimum depth, drag, nonlinear flag, sponge, minimum timestep and maximum timestep semantics. The source projection and propagation grid metrics are kept distinct, as they are in the notebooks. The final timestep is shortened to reach the requested end time. The notebook writes its first sample after the first completed timestep, despite its output threshold initially being zero. That actual timestamp is preserved. Internal RK-stage gauge values are labelled diagnostic stage values, not physical samples at dt, 2dt and 3dt. A separate multi-step fixture checks a wave at a gauge away from its initial source; the reference has 159 completed steps to 240 seconds. This detects an erased nonzero propagated waveform that a stationary source-image check would miss. Gauge coordinates outside the domain no longer silently become edge-cell coordinates. An on-land nearest cell is rejected as an offshore gauge rather than legitimized by H_MIN. The original first-threshold diagnostic and the additional consecutive-saved-samples diagnostic are separate. No crossing remains null, and a genuine zero-time crossing in an externally supplied series remains zero. Observation handling and exports The old controller refers to a fixed DART 21418 March 2011 file and a fixed 2011 event time while the notebook defaults describe Sumatra 2004. The old comparison also removes an offset from the observation. The replacement cannot silently attach that different event to arbitrary model parameters. It requires explicit event-relative, detided observations, an event match, a station that maps to the modelled wet cell and overlapping times. It does not fabricate a research-grade score from hard-coded timing or geography bonuses found in the reporting notebook. Notebook 5's saved output contains a mismatched field/grid export path followed by a file-existence-based success message. The replacement validates current dimensions before constructing a Tecplot output. It never treats an already-existing stale file as evidence that a new export succeeded. The browser export is correctly labelled Tecplot ASCII, not binary PLT. Workflow state and release limits The controller was replaced together with matching HTML/CSS because the archive did not contain the deployed page. Device parity must pass in the current session. Each run builds a CPU reference for its own inputs in a module worker and compares the WebGPU intermediate arrays before propagation. Source, grid, gauge, event and solver changes invalidate old results. Observation edits invalidate old metrics. Cancellation and device errors do not publish partial output as a completed result. The local DOM test demonstrates that a browser without WebGPU remains locked and exposes the failure report. It does not test secure-context deployment, native module fetching, worker execution or a real GPU. Run the delivered device suite in the intended deployed browser before using the simulation results. If it fails, retain the failure report and keep the solver locked; do not increase tolerances or bypass the gate merely to obtain output. These corrections establish a reproducible implementation path. Reproducing the original historical run additionally requires the actual bathymetry and eta0 files. Establishing physical agreement additionally requires the correct event, source model, numerical-resolution study and observational comparison. Neither is implied by the local regression PASS.