Verify
VERIFY
How verification runs and exactly what each check asserts. Source of truth: verify.mjs. Machine-readable result: verification-report.json.
Run
node verify.mjs # exit 0 = all checks pass; exit 1 = any failure
One verification structure runs against two benchmarks:
- Synthetic (always):
generateDataset({n:1200,T:12,seed:7}), 70/30 split. - Official (auto-detected): if
data/official/zonal.csv+
data/official/train-labels.csv exist, the SAME evaluation checks run on real data via out-of-fold k-fold cross-validation, writing data/official/submission.csv.
Checks and what each asserts
Structural (mode-independent):
- dB ↔ linear power invertible —
linToDb(dbToLin(x)) == x, err < 1e-6. - Temporal Lee filter — speckle variance cut > 40%, temporal mean within
10% (src/sar.mjs::temporalLeeFilter).
- Agricultural-extent score monotone — cropland dynamics score above stable
cover.
- Reproducible — same seed → identical MSE (bit-stable).
- Performance budget — trains < 8 s (closed-form ridge).
- Ingestion seam round-trip — long-format zonal CSV parses back into
ordered per-village stacks (src/ingest.mjs).
Evaluation (per active benchmark, identical logic in src/evaluation.mjs):
- Skill vs baseline — model MSE > 30% below the naive column-mean baseline.
- Pooled R² > 0.45.
- Physical constraints — every predicted area in
[0, village_area]. - Total-area recovery — corr(predicted total, true total) > 0.6.
- Submission schema — header exactly
ID,Rice_ha,Cotton_ha,Maize_ha,Bajra_ha,Groundnut_ha; numeric rows; count matches.
Pass/fail semantics
status: PASSrequires every checkpassed === true.proofStatusisPROOF_INCOMPLETEregardless ofPASS, because the official
dataset is a disclosed seam. PASS describes the checks that ran; it does not assert real-data accuracy.
What would invalidate the synthetic claims
- Changing
src/synth.mjssignatures/noise or the seed changes the numbers;
re-run verify.mjs.
- Real data will differ from synthetic; synthetic skill does not transfer
numerically (proof/LIMITATIONS.md).