TERRANOETIS

Methodology & verification

Platform v3.0.0 Docs v3.0.0 VERIFICATION PASS COMPLETED

Approach

  1. Every physics claim is traced to file:line in this repository (engines, kernels, contract layer, UI); where the code itself states limits, they are quoted verbatim.
  2. Claims are then attacked empirically: test suites were run; kernels were executed for representative and boundary inputs; conservation/convergence/benchmark gates were re-executed; a real server boot produced an end-to-end simulation-job transcript.
  3. Where documentation and code disagreed, the documentation was corrected; the code was not modified (this is a documentation pass). Code-level defects found are recorded in the known-limitation register for engineering follow-up.

Execution environment

Machine
Apple M1 (arm64), macOS 26.5.2 — uname -m + sysctl machdep.cpu.brand_string
Node.js
v26.0.0 (node --version) — repository targets ≥ 20 (.nvmrc pins 20)
Python
3.14.5 · NumPy 2.4.2 · SciPy present

Evidence runs

Test suites
CommandResult
npm run test:unit141 files · 1,653 tests passed · 0 failed · 22.85 s wall
npm run test:integration5 files · 49 tests passed · 0 failed · 5.66 s wall
npx tsx engine importEQUATION_ENGINE: 150 keys, ids 1–150, no gaps
npx tsx catalog importPARTS: 7 parts · 26 domains · 150 tools · 0 duplicate ids
node scripts/docs/build.mjs && node scripts/docs/quality-gate.mjssee quality gate below
Kernel executions (per-run detail on each capability page)
KernelRuns executedHeadline evidence
earthquakerepresentative + 2 boundary + 2 invalid + HTTP end-to-endM7.5 → max PGA 251.0 cm/s², MMI 7.0; kernel compute 0.0083 s; job complete 166 ms after submit; M 2.9 and depth 750 km rejected with named validity ranges
wildfirefm2 calibration + fm8 representative + 2 boundaryROS 0.103 m/s vs 0.105 reference → PASS; fm8 mean R 0.370 m/s, I 4,072 kW/m; wall ≤ 1.1 s
hurricaneCat 4 representative + Cat 5 + Cat 1 boundariesphysics gate PASS (V(Rmax)=69.0/70; IB 0.99 cm/hPa; CN75@100 mm 41.1 mm); Cat 4: 77.0 m/s wind, 1.15 m coastal water, 482 mm rain; wall ≤ 1.5 s
floodrepresentative + minimum-rainclosed-box + lake-at-rest gates run; max depth 4.01 m; mass-balance closure 0.0000 %; off-Kaggle output failure observed (D-2)
tsunamiconservation gate + flat-bed ×2 dt + small-box flat ×1 + sloped ×2 dt + REAL GEBCO (Tohoku, via the server’s own opentopodata endpoint) ×2 dtgate |Δ| = 0 PASS; 96²/300 km flat bed stable for 20 min at CFL 0.27 (η 0.64 m, E 0.07 GJ); default-dt flat run diverged; all sloped/real-bed runs diverged (D-1)
volcanobenchmark suite + VEI 3 + VEI 5 boundaryB1–B4 4/4 PASS (Kilauea 2018: 15.0 km modelled vs ~13.5 km observed); mass/ash budgets Δ ≤ 1e-14 relative; M–T plume 27.9 km @ VEI 5
landslidequake-trigger + rain/entrainment + convergence script + calibration gridsconvergence PASS (Δ₂ = 0.050 ≤ 0.25); runout 3.74→2.87→2.95 km over 64/128/256; entrainment ledger 0.0000 % drift

Raw per-run records (stdout, metadata.json, timings) were held outside the repository during this pass; every published number is re-derivable from the reproduction commands and each page’s own command block.

Gates built into the kernels (what runs before results are trusted)

KernelPre-emission gateOn failureSource
earthquakeGMPE sanity (decay, range, site, PGV/PGA ratio, MMI monotonicity, band round-trips)refuses to emit (RuntimeError)kaggle-kernels/earthquake-sim/main.py:194-232,400-404
hurricaneHolland/B/IB/SCS-CN/wave/rainfall physics checksrefuses to emitkaggle-kernels/hurricane-sim/main.py:285-335,717-720
floodclosed-box conservation (1e-9) + lake-at-rest well-balanced (1e-6)raises before runkaggle-kernels/flood-sim/main.py:121-366,771-783
tsunamiclosed-box conservation (flat bed only)raises before run — flat bed leaves the source term untested (D-1)kaggle-kernels/tsunami-sim/main.py:406-417
volcanoflat + steep closed-box conservation (steep checks well-balancedness)raises before runkaggle-kernels/volcano-sim/main.py:607-680,1383-1386
landslideconvergence + conservation via validate_convergence.py (not invoked by main())script exit 1kaggle-kernels/landslide-sim/validate_convergence.py:19-105
wildfireROS reference print (non-fatal)prints CHECKkaggle-kernels/fire-sim/main.py:501-508

Known-limitation register

D-numbered for cross-reference; engineering follow-up recommended. Capability pages already state each limitation where it applies.
#LimitationEvidence
D-1Tsunami solver: three unbounded-growth mechanisms. (1) the main-loop default timestep (0.9·dx/√2c) exceeds the stability bound of second-order MUSCL/HLL — divergence even on a flat bed at printed “CFL 0.90 (OK)”; (2) the roll-based face divergence couples opposite domain edges, so waves grow after boundary interaction (48² box: 0.27 → 22 m in 20 min on a flat bed); (3) on any non-flat bathymetry — including a real GEBCO 2020 sample — the explicit central-difference source (−dt·g·H·∂b/∂x, not well-balanced) drives max|η| → 10^300 m, energy NaN, at every tested dt. The closed-box conservation gate runs on a flat bed where (3) vanishes, so it cannot detect these. Flood/volcano use Audusse-style hydrostatic reconstruction; tsunami does not.kaggle-kernels/tsunami-sim/swe_solver.py:150-151,188-193,235 kaggle-kernels/tsunami-sim/main.py:236-241 reproduced ×9 configs
D-2Standalone local python3 main.py for flood/tsunami/volcano/landslide completes physics but fails writing results (hard-coded /kaggle/working). Consistent with the runner design (Kaggle or in-process import), but it blocks ad-hoc local runs.kaggle-kernels/flood-sim/main.py:786 kaggle-kernels/landslide-sim/main.py:873 observed [Errno 30]
D-3Earthquake: the spectral_acceleration docstring promises a fallback “PGA model scaled by the 1 s/PGA ratio” for other periods; the code returns the unscaled PGA model. Docs describe actual behaviour only.kaggle-kernels/earthquake-sim/main.py:174-178
D-4Hurricane gate comment inconsistency: the docstring quotes “TR-55: CN75, P=100 mm → Q≈28.3 mm” while the enforced tolerance is (30, 50) mm and the measured value is 41.1 mm. Pages cite the tolerance, not the stale comment.kaggle-kernels/hurricane-sim/main.py:291,304-305 gate line observed
D-5Coarse-grid eyewall dilution: when R_max ≲ 2× cell size the sampled wind maximum falls far below V_max (Cat 5, RMW 5 km on 2.5 km cells → 32.2 m/s). A sampling limit of point-vortex parametrics on discrete grids, not a code fault.kaggle-kernels/hurricane-sim/main.py:484 observed
D-6Wildfire front advance is stochastic-ignition-rate-limited: measured burned area trails the continuous ROS field (0.15 % of grid in 6 h, fm8). The code documents the slow-fuel stall failure mode and its residence-time fix.kaggle-kernels/fire-sim/main.py:521-543,589-593 observed
D-7Landslide main() does not invoke its own closed-box verifier (defined but uncalled); the authoritative gates are validate_convergence.py and the calibration path. In-domain ledger drift 1.56 % observed without entrainment (boundary exchange booked separately).kaggle-kernels/landslide-sim/main.py:712-714,808-857 observed
D-8Flood “Green-Ampt constant loss rate” is a fixed 10 mm/hr modulated by saturation — not the Green–Ampt equation. Label kept as in source; described as implemented.kaggle-kernels/flood-sim/main.py:57,470-471
D-9Wire constants with no physics: flood dam_breach is a schema literal with no breach hydrograph in the kernel; flood wind_speed_ms and tsunami hypocentre depth are UI/context fields that never enter the solve.src/services/kaggleSim.ts:37-38 kaggle-kernels/flood-sim/main.py:370-380
D-10Determinism caveats: wildfire honours seed (optional — unseeded otherwise); wall-clock caps truncate runs machine-dependently (kernels ≤ 480 s; local server timeout 120 s); synthetic fallbacks are fixed-seed. All timing figures here are single observations on one machine.kaggle-kernels/fire-sim/main.py:407-415,568-570 server/kaggle/simRunner.ts:134

Discrepancy log — documentation errors found & fixed

The code was treated as authoritative in every case; sources of truth updated in the second verification pass.
#ClaimVerified correctionFixed in
C-1“7 physics simulations — 3 run locally on CPU, 4 on free Kaggle GPU kernels” (README)Kernels are NumPy-only (0 cupy/CUDA imports); only flood-sim requests the Kaggle GPU accelerator; the other routed kernels have enable_gpu=false. “Kaggle kernels” is accurate; “GPU kernels” is not.README.md · DEPLOYMENT.md · BACKEND.md · modes table
C-2“82 with resolvable DOIs” (README/MODELS.md)80 of 150 model references contain a DOI string (12 ISBN, 4 explicit NO-DOI); counting method now stated.README.md · MODELS.md
C-3Redis handles “PubSub · Queue” (ARCHITECTURE.md topology + BACKEND.md)The event bus is an in-process EventEmitter (server/pubsub.ts); Redis serves cache + memory hot path.ARCHITECTURE.md · BACKEND.md
C-4Repository tree lists server/digitalTwin/ (README)Directory does not exist (disk + git ls-files).README.md
C-5“sandboxV2: Simulation engines (FARSITE, ADCIRC, WRF, HYSPLIT)” (README/BACKEND/ARCHITECTURE)Files are simplified surrogates named *Lite (cellular ROS; storm-surge SWE; dispersion particle model; idealized WRF-style driver) plus an FNO surrogate — not the operational models.BACKEND.md · ARCHITECTURE.md · README.md
C-6“1,600+ tests” / “1624+ tests” (README/CONTRIBUTING)Measured today: 1,653 unit + 49 integration passing.README.md · CONTRIBUTING.md
C-7“Playwright browser tests (7 specs, 12 tests)” (README)7 spec files; 15 test() declarations at line start, 14 registered by default per npx playwright test --list (“Total: 14 tests in 7 files”; the one extra land-cover test self-skips unless LULC_HEAVY=1). An earlier fix-note here stated “38 declarations” — that count came from a naive grep "test(" that also matched regex .test( calls; corrected by direct enumeration.README.md · documentation hub
C-8Landing copy: “GPU-accelerated mathematical models computed directly over real 3D terrain meshes” (platform-overview)Simulation math runs on CPU (NumPy); fields are rendered on the WebGL globe client-side.old marketing claim removed; the rebuilt landing and docs hub state the accurate wording
C-9docs/index.html was only a redirect to the marketing pageThe site is now navigation-first from index.html; platform-overview.html preserved as a redirect stub so inbound URLs keep resolving.docs/index.html · docs/platform-overview.html
C-10App shell “~11,000 lines”, “11 panels”, “41 modules” (approximations)Measured: 11,038 lines; 11 lazy panels; 41 rendering modules.now stated as measured counts
C-11Second verification pass (re-executed kernels, suites, boot; line-by-line claim audit)Nine fixes: e2e suite counts “38 declarations” (naive grep artifact) → 15 declarations / 14 registered; handler count 371 (literal app|router only) → 398 across all router identifiers; “~100 provider keys” → 103 variables (62 key/token/secret); “archived example artifacts in kaggle-kernels/results/” → directory is empty and gitignored; error shape → two coexisting forms (string from handlers, {error:{code,message}} from central middleware); public-route wording → tiles/pulse/shared are public and unthrottled; phantom “vault” module removed from routes/ inventory; “OpenTelemetry” relabelled as in-house OpenTelemetry-style tracing (official SDK imports are stubbed); Pages deployment paragraph → docs/site/ via deploy-docs.yml; landing prerequisites badge “PYTHON 3.12+” → “PYTHON 3 + NumPy” (nothing enforces 3.12).README.md · SECURITY.md · CONTRIBUTING.md · API.md · BACKEND.md · ARCHITECTURE.md · DEPLOYMENT.md · FRONTEND.md · MODELS.md · getting-started.md · capability pages · this site

Claims not verifiable in this environment

ItemWhy
Kaggle push → poll → download transportWould push to the maintainer’s Kaggle account; deliberately not performed
GPU-accelerated instance behaviourNo kernel uses GPU code; acceleration flags are metadata only
LLM provider call success/latencyExternal paid providers
Live-feed correctness per providerExternal data churn; not asserted in prose
Playwright pass stateChromium/WebGL environment; not run
ClickHouse / TimescaleDB / Kafka scaling pathsOptional backends not deployed

Documentation quality gate

node scripts/docs/quality-gate.mjs fails CI on: broken internal links (HTML↔HTML, HTML→MD, MD→MD, MD anchors), missing anchor targets, missing per-page metadata (title, description, canonical, og, last-reviewed, version), unresolvable file:line citations (target must exist; the cited range must fit the file), banned marketing vocabulary, and build drift (build.mjs --check). Wired into .github/workflows/docs.yml on every docs-affecting push/PR.

Reproduction quick sheet

Everything the site claims as measured, in one block

npm run test:unit && npm run test:integration

npm run dev:server &   # then:
curl -s -X POST localhost:3001/api/kaggle/simulate -H "Content-Type: application/json" \
  -d '{"type":"earthquake_swarm","lat":36.1,"lon":139.7,"grid_size":128,"extent_km":100,"magnitude":7.2,"depth_km":15,"vs30":760}'

# tsunami: flat vs sloped bed (D-1) — run from kaggle-kernels/tsunami-sim:
python3 <<PY
import numpy as np, swe_solver as S
y, x = np.mgrid[0:48, 0:48]
flat = np.full((48,48), 4000.0); sloped = 4000 - 500*x/47
h0 = np.exp(-(((x-24)**2+(y-24)**2)/(2*6.0**2)))*1.2
for name, bed in [("flat", flat), ("sloped", sloped)]:
    h, hu, hv = h0.copy(), np.zeros_like(h0), np.zeros_like(h0)
    for _ in range(200): h, hu, hv = S.step_shallow_water(h, hu, hv, bed, 3.0, 3125.0, 3125.0)
    print(name, "max|eta| = %.3e" % np.abs(h).max())   # observed: flat 1.17e+01 m (wrap growth), sloped 5.81e+03 m
PY

cd kaggle-kernels/volcano-sim/benchmarks && python3 run_benchmarks.py    # B1–B4
cd kaggle-kernels/landslide-sim && python3 validate_convergence.py       # gates
node scripts/docs/build.mjs && node scripts/docs/quality-gate.mjs