Skip to content

Commit the guides' tutorial data instead of fetching it at build time - #511

Merged
GondekNP merged 3 commits into
feat/runnable-static-docsfrom
feat/docs-committed-tutorial-data
Aug 4, 2026
Merged

Commit the guides' tutorial data instead of fetching it at build time#511
GondekNP merged 3 commits into
feat/runnable-static-docsfrom
feat/docs-committed-tutorial-data

Conversation

@GondekNP

@GondekNP GondekNP commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

The two data-driven guides declared what data they need, but the files were not in the repository.
They were preprocessed on every push from a zip fetched over the network — landing/test_preprocess.sh:19
does wget https://joshsim.org/guides/raw_tutorial_supplement.zip, from the site the build publishes to.

So the input to the build was a mutable URL. If that zip changes, the published guides change with
no commit and no diff. If it 404s, four jobs fail. This commits the data instead.

Why this is affordable

.jshdz is XZ-wrapped .jshd, and it compresses extraordinarily well:

file .jshd .jshdz
precipitation 0.71 MB 23 KB 32×
precipitationTulare 1.40 MB 6 KB 225×
temperatureTulare 1.40 MB 5 KB 296×
total 3.5 MB 34 KB

34 KB against a 64 MiB pack. The repo already commits four .jshd files under paper/, so
committing data is not a new policy here — only the compression is.

Why nothing else had to change

MultiFormatExternalGetter resolves a bare external name to <name>.jshdz before <name>.jshd, so
external precipitation finds the compressed file with no model edits and no jar changes. And
because the committed name already matches the external name, the rename the old pipeline needed
(precipitation_geotiff.jshdprecipitation.jshd) goes away.

The one constraint

.jshdz is JVM-only — the XZ decoder is not compiled through TeaVM (build.gradle:47). The
guides tell readers to upload the data into the browser editor, so the site must keep serving
.jshd. deployStatic now expands each committed file as it stages the guides, which also retires
the hardcoded three-file copy: the guide directory names the destination, so adding a guide with
data needs no change there.

The page says this out loud rather than leaving a reader puzzling over a filename they cannot find —
the Data row names the file as the repository stores it and notes that the download is the expanded
form.

CI simplification

job before after
testPreprocessing runs preprocess, uploads artifact runs preprocess — no longer decides what ships
testGuideExamples downloads artifact reads the repo
testAdditionalFeatures downloads artifact the download was dead — none of its four scripts read it
deployStatic downloads artifact, hardcoded 3-file copy expands from the repo, generic

testPreprocessing keeps running: exercising preprocess against netCDF and GeoTIFF is worth doing.
It just no longer decides what ships.

Also carried

The first commit declares the data: field on both guides, which was missing — the manifest recorded
that the models reach precipitationTulare/temperatureTulare/precipitation but not which files
provide them. The harvest now fails both when a runnable unit reads an external no declared file
provides, and when a declared file is not beside its model — a check the field could not have while
the data lived in an artifact. Conformance tests are exempt from the first; their fixtures are staged
by the test harness.

Verification

  • xz -d returns the published bytes exactly — all three round-trip byte-identical to what the
    site serves today
  • The deploy step was simulated locally: produces the same three paths with identical bytes
  • Run time is unchanged: two_trees takes 24s from .jshdz against 26s from .jshd
  • examples/test_guide_examples.sh passes against the committed data, from a clean tree with no
    hand-staged files
  • 164 Python tests pass, ruff clean. Negative controls confirmed: a typo'd data name and a
    declared-but-absent file each fail the harvest with a file and line

Known gaps

  • examples/test.sh also stages from landing/preprocessed_data/ and is in no workflow — the
    same shape as paper/management/test.sh. Left alone; nothing fed it before this change either.
  • landing/test_preprocess.sh still wgets the raw zip. That is now only in the test path, not the
    publish path. Making it diff its output against the committed copy — so a preprocessing regression
    fails the build instead of quietly changing the guides — needs byte-reproducible preprocess
    output, which I have not verified.
  • deployStatic is skipped on PRs, so its rewiring first runs when this reaches dev.

🤖 Generated with Claude Code

GondekNP and others added 3 commits August 4, 2026 21:43
two_trees and grass_shrub_fire are the only library units that read an
external, and neither declared a data file. The manifest recorded that the
models reach precipitationTulare/temperatureTulare/precipitation but not
which files provide them, so the rendered pages showed no Data row.

That gap is worse than a missing label. .gitignore excludes *.jshd and CI
preprocesses the tutorial data into an artifact, so the declaration is the
only record in the repository that a run needs the file at all -- a reader
who downloaded the model got "External resource not found" naming a file
the page never mentioned.

The harvest now fails when a runnable unit reads an external no declared
file provides, pointing the author at the sidecar. Conformance tests are
exempt: the test harness stages their fixtures, sometimes generating them,
so the author of a test does not own the file. Verified by staging only the
declared files -- both guides run to exit 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The two data-driven guides declared what they need but the files were not
in the repository. They were preprocessed on every push from a zip fetched
over the network -- landing/test_preprocess.sh wgets it from joshsim.org,
the site the build publishes to -- so the input to the build was a mutable
URL. A change in it would alter the published guides with no commit and no
diff, and a 404 would fail four jobs.

Compression is what makes committing viable. .jshdz is XZ-wrapped .jshd,
and the three files are 3.5 MB expanded against 34 KB compressed. The
engine reads them directly: MultiFormatExternalGetter resolves a bare
external name to <name>.jshdz before <name>.jshd, so no model changes and
neither does a run. Measured at 24s versus 26s for two_trees, and xz -d
returns the published bytes exactly.

The harvest now also fails when a declared data file is not beside its
model, which the field could not check while the data lived in an artifact.
The page names the file as the repository stores it and says why the
download beside it has a different extension: .jshdz is JVM-only, since the
XZ decoder is not compiled through TeaVM, so the browser editor a reader
uploads into can only take .jshd.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Four jobs passed the tutorial data around: testPreprocessing uploaded it,
and testGuideExamples, testAdditionalFeatures, and deployStatic each
downloaded it. Now that the data is committed, all of that goes -- one
upload, three downloads, and a cross-job dependency.

testAdditionalFeatures never used what it downloaded: none of the four
scripts it runs reads landing/preprocessed_data, and the ForeverTree test
beside them reads the .jshd files already committed under paper/.

testPreprocessing keeps running, because exercising `preprocess` against
netCDF and GeoTIFF is worth doing. It just no longer decides what ships.

deployStatic expands each committed .jshdz as it stages the guides, which
also retires the hardcoded three-file copy: the guide directory names the
destination, so adding a guide with data needs no change there. Verified
locally that the step produces the same three paths with bytes identical
to what the site serves today.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant