SWMM MOONSHINE · ROUND-TRIP VERIFIER — SWMM5 ⇄ SWMM6

ENGINE A · SWMM5 INP —RPT —OUT —

Drop .out (+ .rpt / .inp) here, or

ENGINE B · SWMM6 / SWMM5+ INP —RPT —OUT —

Drop the second engine's set here, or

FOLDER QUEUE — PICK A SET FOR EACH ENGINE

PER-ELEMENT DELTAS

CLICK A ROW TO INSPECT · CLICK HEADERS TO SORT · TABLE CAPS AT 400 ROWS, CSV IS UNCAPPED
load two result sets — or press DEMO

WHAT THIS PROVES · HOW TO READ IT

The claim being tested, stated precisely: the selected per-element result summaries and series agree within the stated tolerances. That is deliberately narrower than "the same physics" — a certificate is only as strong as the metrics behind it, and this one now checks peak magnitude and integrated volume as required metrics, with whole-series NRMSE and peak timing as advisory metrics, all gated behind hard compatibility checks (exact flow units, identical time grids, complete engine runs, matching record sets, mass-conserving continuity). Left grid = every result record from engine A. Right grid = the same records from engine B. Green dots agree within tolerance, amber are near the line, red diverge, hollow gray exist on one side only. The dashed fan samples the worst disagreements — each ray flies from the model to a circled element so your eye lands exactly where the engines differ. The banner underneath is the certificate: counts, tolerances, worst offender, continuity from each .rpt, and three SHA-256 hashes per side with distinct meanings: RAW fingerprints the .out bytes (proves byte identity), RESULTS fingerprints only the stored results block (every timestamp and value, headers excluded), and SUMMARY fingerprints the canonical per-element peak/time/integral table at documented precision (6 significant digits, 4-decimal hours). A summary hash can theoretically collide across materially different series — that is why it is labeled SUMMARY and why the identity tiers are decided by the raw and results hashes, never the summary. Click the hash line to copy all six.

THE MOONSHINE HOMAGE

Layout borrowed with admiration from Mike Dupont's (@introsp3ctor) animated moonshine visualizer. Monstrous moonshine is the discovery that two unrelated mathematical worlds carry the same numbers: in 1978 John McKay noticed the modular j-function's coefficient 196884 equals 196883 + 1 — dimensions from the Monster group's character table. Conway and Norton conjectured the full correspondence; Borcherds proved it in 1992. An engine benchmark makes the same kind of claim — two independent computations, one shared truth — so the poster grammar transfers: record grids, sampled traces, a round-trip certificate, and one headline pair of numbers that ought to match.

MAPPING · ORIGINAL → SWMM

MOONSHINE VISUALTHIS APP
irrep / character records gridengine A per-element result records
moonshine q-series records gridengine B per-element result records
radial fan of sampled chainstop-K elements by |Δ| (identity runs sample by magnitude instead)
three-shell globemagnitude shells — bigger |Δ| lands on the outer shell
✓ machine-checked round tripcounts + tolerances + max Δ + continuity + SHA-256 per table
dim ρ155 prime factorizationactive element expanded: peaks, timing, inflow decomposition, sparkline overlay
196883 ⇄ 196884 identity cardpeak system outflow, engine A ⇄ engine B, Δ printed on the dashes
24-second lossless looptrace loop in-app + self-contained SMIL animated-SVG export

FILES · FORMATS · HONEST LABELS

Reads standard EPA SWMM5 binary .out files (magic 516114522), any build that writes that format — including SWMM5+/SWMM6 builds that keep .out compatibility. The .rpt is optional and contributes continuity errors, warnings, and the engine version line to the certificate. The .inp is optional and only labels the set. The two DEMO buttons generate synthetic .out files in-browser (seeded, byte-identical every run) — they exercise the real parser end-to-end but are not engine output; the poster says SYNTHETIC DEMO whenever they are loaded. The Δ table, certificate, and hashes are computed from parsed values only — nothing is asserted that wasn't read from the files.

VOCABULARY OF THE CERTIFICATE

ΔPEAK% = 100 · |A − B| / max(|A|, |B|) on each element's peak; ΔVOL% is the same formula on the integrated series (∫ dt, unit·h); NRMSE% = 100 · RMSE(A,B) / max(peak A, peak B) over every reporting period — computed only when time grids match exactly. Required metrics (peak, volume) drive FAIL; advisory metrics (NRMSE, ΔtP against TOL ΔtP) can raise WARN but never FAIL. The fan and WORST line rank by the composite max(ΔPEAK, ΔVOL, NRMSE). Absolute floors are per quantity — ABS Q in flow units for flow-type records, ABS D in length units for depth/head — so one number no longer masquerades as both. OK: Δ% ≤ tolerance, or Δabs ≤ absolute floor (protects near-zero records from percent blowup). WARN: within 5× tolerance. FAIL: beyond it. ONLY-A / ONLY-B: the element exists in one table only — an automatic certificate failure because the record sets are not the same shape. Unit systems are read from each .out; a US ⇄ SI mismatch is flagged and fails the certificate rather than comparing unlike numbers.

SAME-ENGINE RUN COMPARISON

The A/B slots take any two SWMM5-format .out files — nothing requires two engines. Load the same model run twice with different options (LENGTHENING_STEP on/off, routing step, INERTIAL_DAMPING, surcharge method), a calibration before/after, or a pre/post model-edit pair, and the fan ranks exactly which elements the change moved. MODE changes vocabulary only (RUN A ⇄ RUN B vs SWMM5 ⇄ SWMM6), never the math. AUTO reads the output version code inside each .out and defaults to run mode when both codes match. A matching code identifies a reported version and compatible output layout — not a unique executable fingerprint — so confirm the builds via the .rpt version lines (shown in the certificate) or an executable hash when it matters. In run mode a ✗ DIVERGENCE verdict is not a failure; it is the sensitivity finding, itemized worst-first.

TIMING, CONTINUITY, AND THE AMBER BAND

The ΔtP column reports the peak-timing shift (B − A, hours) — the classic dynamic-wave phase drift that magnitude comparison misses. The divergent demo plants one on C5: its Δ% is noise-level OK while its peak is seeded 0.3 h late and reads +0.25 h in the table — the gap is report-step quantization (tPEAK snaps to the 300 s reporting grid), itself worth knowing when you compare timing. Sort the column and C5 surfaces instantly. Timing does not yet gate the status bands (roadmap), it is surfaced for the modeler's judgment. The continuity gate does judge: if either .rpt reports |routing continuity| > 5%, the certificate goes ✗ CONTINUITY SUSPECT regardless of element deltas — a run that doesn't conserve mass can't certify anything. No .rpt, no gate (load the reports). The NEAR-MISS demo fills the band the vocabulary defines but the other demos skip: every seeded delta lands inside the amber 5× warning band, zero failures — a ✓ verdict that still tells you where to look.

THEMES

The verifier opens dark, always. DARK · LIGHT · AUTO in the header switches a complete second palette — poster, grids, fan, certificate, badge, and exports all repaint from one theme table, and AUTO follows your OS setting live. Theme changes nothing but colour: every number, verdict, and hash is computed identically in both, and the suite asserts it. Your choice persists and rides the share-URL (th=…).

ON A PHONE

Below 700 px the poster keeps a readable 760-unit width and pans horizontally; below 640 px the delta table drops to its essential columns — KIND, NAME, Δ%, ΔtP, STATUS — with every column always in the CSV. Fan endpoints carry an enlarged invisible tap target so a fingertip lands the trace a mouse pointer would.

SHARING A VERDICT

Mode, tolerances, trace count, metric, and the loaded demo live in the URL hash — copy the address bar and the link reopens the same verdict (deployed builds; sandboxed previews may block hash writes). Click the SHA-256 line to copy both full hashes. BADGE exports the certificate alone as a small standalone SVG — a README-ready machine-checked stamp carrying verdict, counts, tolerance, worst offender, and both hash prefixes.

RECORDING DEPENDENCIES — A DECLARED TRADEOFF

The GIF recorder loads html2canvas and gif.js from cdnjs; everything else in this file is self-contained. Inlining them would quadruple the file for an auxiliary feature, so instead the button self-checks: libraries missing → it disables and says so; gif.js alone missing → it relabels RECORD WEBM. The verifier itself never depends on the network.

ROADMAP

Interpolated time-grid alignment (compare mismatched grids instead of withholding) · correlation/shape score joining NRMSE · deep .inp geometry diff (endpoints, inverts, sections, roughness — the fingerprint row currently proves textual identity only) · timing promoted from advisory to required with a quantization-aware tolerance · presentation mode · CSV ingest for engines that don't write .out · repo browser with sibling auto-fetch across a whole benchmark folder · optional in-browser SWMM WASM run so engine A can be generated from the .inp directly.

SWMM MOONSHINE ROUND-TRIP VERIFIER · POSTER GRAMMAR AFTER @INTROSP3CTOR'S MOONSHINE VISUALIZER · SAME MODEL — TWO ENGINES — THE SAME NUMBERS
BUILT WITH THE SWMM5 .OUT FORMAT AS WRITTEN BY EPA OUTPUT.C · v2026.08.22 · r7
WORKING…