commits
- Fix Os.mkdir EEXIST race when concurrent forked workers create the same
package directory (root cause of ~370 cascade failures in roll-forward)
- Add on_cascade callback to execute_dag for cascade root-cause logging
and skeleton layer creation (layer.json + opam-repository for rerun)
- Extract shared helpers: Util.populate_opam_repository,
Util.write_skeleton_layer, Util.wait_for_layer_json
- Refactor execute_dag internals: deduplicate propagate_failure,
promote_dependents, and complete_node into single definitions
- Use Unix._exit in forked children to avoid flushing parent buffers
- Replace Str with thread-safe pure-string substring matching
- Add Unix.lockf file locking to History.append for concurrent writes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Both commands now read opam_repositories (and local_repos) from
build-config.json, which is written by batch. There's no reason to
specify it separately — these commands always operate on a cache
that was set up by a prior batch run.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Every sudo and exec call now logs the full command line with timestamps
to the per-PID log file. Non-zero exit codes are also logged. DAG
completions log the package name, hash, and status.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of forking per-target (where each child independently walks
the full dependency chain), build a global DAG of unique build layers
across all solutions and execute in topological order. This ensures
shared dependencies (e.g., the compiler) are built once before their
dependents are launched, maximizing actual parallelism at each tier.
The DAG executor:
- Flattens all solutions into deduplicated build nodes keyed by hash
- Topologically sorts the global DAG
- Maintains a ready-queue of layers whose deps are all built
- Launches up to N concurrent runc containers
- Handles cache hits (pre-existing layers) without forking
- Propagates dependency failures without building
The sequential (--fork 1 / no --fork) path is unchanged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Include base image hash in build layer hash so changes to opam-build
or OS config correctly invalidate all cached layers
- Add base_hash to all Container backends (linux, freebsd, windows, dummy)
- Cache base_hash result to avoid repeated git subprocess calls per layer_hash
- Add --fork N to cascade command for parallel reruns
- Support --local-repo for opam-build: copies into Docker build context
- Fix cascade to scan current state for dependency_failure targets
- Fix blessed status propagation through cascade via --was_blessed
- Optimize batch summary: lazy layer lookups, in-memory dedup, hash memoization
- Record rerun/cascade results in history and regenerate status.json
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Design doc covers the data model (JSONL history, status.json), failure
categories, CLI commands, log retention policy, and agent operational
loop for the docs CI replacement.
Implementation plan breaks the work into 15 tasks with dependency graph.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add `day10 cascade` to rerun reverse dependencies of recently fixed
packages (those that transitioned to success), and `day10 gc` for
log retention with history compaction and run archival/deletion.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- rerun: retry failed builds by hash or package name, with --force to clear cached layers
- rdeps: reverse dependency lookup from cached solutions, with --failing filter
- notify: pluggable notification system supporting slack, zulip, telegram, email, stdout
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- query: show package build details with optional --history flag
- failures: list failing packages with --blessed and --category filters
- changes: show status transitions since last run
- disk: show disk usage breakdown by layer type
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reads status.json from the cache directory and displays current build
state including run info, blessed/non-blessed totals, changes, and new
packages. Supports both text and JSON output formats via --format flag.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After history entries are recorded and the batch summary is printed,
call Status_index.generate and write to produce status.json. Also
prints a summary of any status changes and new packages detected.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Extract compiler version from layer.json deps field instead of using
empty string - searches for ocaml-base-compiler or ocaml-variants
2. Record dependency_failure entries for packages that have no build
layer by comparing solutions against scanned layers
3. Deduplicate history entries by checking for existing run_id +
build_hash before appending
4. Record doc success entries for blessed packages, not just failures
Also extract matches_any helper to clean up classify_build_failure and
doc category detection.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Check the doc error message for "link" (case-insensitive) to categorize
doc failures as doc_link_failure vs doc_compile_failure, so both categories
are produced in the history.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add record_build_result helper and classify_build_failure for pattern-matching
build logs against transient/depext failure categories. Record history entries
in print_batch_summary for build successes, classified build failures, and
blessed doc failures. Record solver failures after the solve phase in run_batch.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements Status_index with JSON serialization, generation from
package history files, change detection between runs, and atomic
file writes. Scans package directories, tallies blessed/non-blessed
totals by category, detects status changes and new packages.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements append-only JSONL storage for build history entries with
functions for reading, filtering by build_hash/blessed status, and
compacting old entries. This is the foundation for CI status tracking.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
gen_blog_index.exe now writes into _blog_gen/ directory (instead of
overwriting in place) and runs from site/ cwd. dune.inc gains a
(dir _blog_gen) rule plus per-index diff rules under @runtest, so
`dune runtest site/` detects stale indexes and `dune promote` updates them.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Scan site/blog/ instead of blog/
- Write indexes to site/blog/ paths
- Use !/jon-site/blog/ odoc references (matching existing indexes)
- Accept both 4-part and 5-part path splits for flexibility
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@published is now a custom tag in Comment.docs.elements, not in
Frontmatter.other_config (which no longer exists). Extract it by
scanning page.content for `Custom ("published", payload) tags.
Also update odocl search path to _build/default/site/_odoc/blog
and fix dune dependencies (drop ppx_deriving_yojson, add odoc.html
odoc.document odoc.model fmt tyxml).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New blog posts:
- 2026/02 weeknotes weeks 7-8, odoc notebooks fun
- 2026/03 weeknotes week 9 (with mapdemo.mov and search.png)
Scripts: gen_atom (Atom feed), gen_blog_index, mld helpers
Also adds interactive_map notebook.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Interactive mode was incorrectly set to read-only, preventing users
from typing in code cells. Interactive cells should be editable with
ephemeral changes (lost on refresh), unlike Exercise cells which
persist edits to localStorage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Both interactive and scrollycode extensions now check
_build/install/default/share/x-ocaml/x-ocaml.js (walking up from CWD)
before falling back to opam share. This avoids requiring 'dune install
x-ocaml' as a separate step.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Install odoc-jon-shell, odoc-interactive-extension, and
odoc-scrollycode-extension instead of x-ocaml (which doesn't need
installing since it's found from _build/install/)
- Fix odoc.support copy to use mkdir -p and glob pattern
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Commands sent before Leaflet finishes loading were silently dropped.
Now they are queued and replayed once the map initializes. This fixes
enableBboxDraw being lost when called immediately after display_managed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add tessera-geotessera-jsoo and tessera-viz-jsoo to the jtw opam
universe so the interactive map notebook can load them.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Self-contained HTML shell plugin that inlines all CSS and JS into
each page. Font URLs rewritten to Google Fonts CDN for odoc fonts
and jsDelivr CDN for KaTeX fonts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
71fe7ccd3 Merge branch 'point-release-fixes' of https://github.com/jonludlam/odoc
4d53f50da Make all warnings respect --warn-error
d1f796f14 Add test showing --warn-error doesn't affect unresolved references
d6c8ece57 Don't resolve imports without digests during compile
18adbf89b Add test for no-alias-deps import resolution bug
c3f0f46ee Update for dune 3.21
git-subtree-dir: odoc
git-subtree-split: 71fe7ccd36eee7f244a355653e10de197d6bcb94
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests addMarker, clearMarkers, addImageOverlay, removeImageOverlay
commands in a standalone HTML page.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New commands:
- enableBboxDraw: custom rectangle drawing with bbox_drawn event
- addImageOverlay/removeImageOverlay: display data URL images on map
- addMarker/clearMarkers: circle markers with labels
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests PNG encoding and data URL generation in a web worker.
Verified: 4x4 RGBA image encodes to valid PNG, renders as <img>.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests run in a web worker (sync XHR requires worker context).
Fetches a real scales.npy from dl2.geotessera.org, parses it,
and verifies the shape and data values.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Widen sidebar from 200px to 260px with updated max-width calculations
- Collapse top two wrapper levels so content aligns with header
- Add border-left indentation guides on nested lists
- Replace original toggle arrows with larger inline chevrons (1em, rotate on expand)
- Separate click targets: chevrons toggle expand/collapse, links navigate
- Align childless items with toggle items via 20px margin-left
- Fix CSS cascade where .jon-shell-main ul overrode sidebar ul padding
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add browser test that compiles OCaml to JS via js_of_ocaml and verifies
fetch, npy parsing, and mosaic assembly work in a real browser.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of requiring every .mld file to specify @x-ocaml.universe and
@x-ocaml.worker tags individually, configure the default universe path
once in dune-workspace (--config x-ocaml.universe=/_opam). The shell
emits <meta> tags from config values, and per-page @x-ocaml tags can
still override them.
Changes:
- dune-workspace: add --config x-ocaml.universe=/_opam to html_flags
- gen_rules.ml: pass --config to odoc html-generate for @site build
- odoc_jon_shell.ml: emit <meta> tags from x-ocaml.* config values
- odoc generator.ml: pass config to shell page_creator
- interactive_extension.ml: upsert meta tags (update existing or create)
- x_ocaml.ml: infer jtw backend from x-ocaml-universe meta tag
- Remove @x-ocaml.universe/@x-ocaml.worker from 14 .mld files using
the default /_opam universe
- deploy-site.sh: add dune install x-ocaml, chmod fix, widget-leaflet
- findlibish.ml: module detection fallback via jsoo runtime
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Generate tessera-viz.opam from dune-project. All odoc documentation
is in the .mli with section headers and docstrings for every public
type and function.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add color_of_hex for parsing hex color strings and classification_to_rgba
for mapping integer class predictions to colored RGBA pixels. Unknown
classes render as black. Add unit arg to resolve optional alpha parameter.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Convert 3-component PCA matrix to false-color RGBA image with
per-component percentile clipping and 0-255 scaling. Optional args
moved before positional to satisfy OCaml's optional-arg resolution.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add the tessera-viz library skeleton with dune-project, .mli interface,
and a working percentile function with linear interpolation. Other API
functions are stubbed with failwith for TDD iteration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Generate opam file from dune-project. All 15 tests pass across grid
math, dequantization, mosaic, and fetch_mosaic_sync.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add end-to-end test for fetch_mosaic_sync using mock fetch function
with numpy fixture files. Verifies the full pipeline: bbox -> tile
enumeration -> fetch -> dequantize -> mosaic -> correct output values.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add mosaic tests verifying horizontal and vertical tile assembly.
North tiles appear at top (row 0), south at bottom. Confirms correct
grid position calculation and data placement.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add dequantization test with numpy fixtures (2x3x4 int8 embeddings,
2x3 float32 scales). Verifies correct int8 * scale multiplication
and output matrix dimensions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add new tessera-geotessera library with dune project structure, public
API (.mli), and grid math implementation (snap_to_grid, tiles_for_bbox,
tile_name, URL construction). Includes full implementations of
dequantize, mosaic, and fetch_mosaic_sync. Grid math tests all pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix Os.mkdir EEXIST race when concurrent forked workers create the same
package directory (root cause of ~370 cascade failures in roll-forward)
- Add on_cascade callback to execute_dag for cascade root-cause logging
and skeleton layer creation (layer.json + opam-repository for rerun)
- Extract shared helpers: Util.populate_opam_repository,
Util.write_skeleton_layer, Util.wait_for_layer_json
- Refactor execute_dag internals: deduplicate propagate_failure,
promote_dependents, and complete_node into single definitions
- Use Unix._exit in forked children to avoid flushing parent buffers
- Replace Str with thread-safe pure-string substring matching
- Add Unix.lockf file locking to History.append for concurrent writes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of forking per-target (where each child independently walks
the full dependency chain), build a global DAG of unique build layers
across all solutions and execute in topological order. This ensures
shared dependencies (e.g., the compiler) are built once before their
dependents are launched, maximizing actual parallelism at each tier.
The DAG executor:
- Flattens all solutions into deduplicated build nodes keyed by hash
- Topologically sorts the global DAG
- Maintains a ready-queue of layers whose deps are all built
- Launches up to N concurrent runc containers
- Handles cache hits (pre-existing layers) without forking
- Propagates dependency failures without building
The sequential (--fork 1 / no --fork) path is unchanged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Include base image hash in build layer hash so changes to opam-build
or OS config correctly invalidate all cached layers
- Add base_hash to all Container backends (linux, freebsd, windows, dummy)
- Cache base_hash result to avoid repeated git subprocess calls per layer_hash
- Add --fork N to cascade command for parallel reruns
- Support --local-repo for opam-build: copies into Docker build context
- Fix cascade to scan current state for dependency_failure targets
- Fix blessed status propagation through cascade via --was_blessed
- Optimize batch summary: lazy layer lookups, in-memory dedup, hash memoization
- Record rerun/cascade results in history and regenerate status.json
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- rerun: retry failed builds by hash or package name, with --force to clear cached layers
- rdeps: reverse dependency lookup from cached solutions, with --failing filter
- notify: pluggable notification system supporting slack, zulip, telegram, email, stdout
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Extract compiler version from layer.json deps field instead of using
empty string - searches for ocaml-base-compiler or ocaml-variants
2. Record dependency_failure entries for packages that have no build
layer by comparing solutions against scanned layers
3. Deduplicate history entries by checking for existing run_id +
build_hash before appending
4. Record doc success entries for blessed packages, not just failures
Also extract matches_any helper to clean up classify_build_failure and
doc category detection.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add record_build_result helper and classify_build_failure for pattern-matching
build logs against transient/depext failure categories. Record history entries
in print_batch_summary for build successes, classified build failures, and
blessed doc failures. Record solver failures after the solve phase in run_batch.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements Status_index with JSON serialization, generation from
package history files, change detection between runs, and atomic
file writes. Scans package directories, tallies blessed/non-blessed
totals by category, detects status changes and new packages.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
gen_blog_index.exe now writes into _blog_gen/ directory (instead of
overwriting in place) and runs from site/ cwd. dune.inc gains a
(dir _blog_gen) rule plus per-index diff rules under @runtest, so
`dune runtest site/` detects stale indexes and `dune promote` updates them.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@published is now a custom tag in Comment.docs.elements, not in
Frontmatter.other_config (which no longer exists). Extract it by
scanning page.content for `Custom ("published", payload) tags.
Also update odocl search path to _build/default/site/_odoc/blog
and fix dune dependencies (drop ppx_deriving_yojson, add odoc.html
odoc.document odoc.model fmt tyxml).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
71fe7ccd3 Merge branch 'point-release-fixes' of https://github.com/jonludlam/odoc
4d53f50da Make all warnings respect --warn-error
d1f796f14 Add test showing --warn-error doesn't affect unresolved references
d6c8ece57 Don't resolve imports without digests during compile
18adbf89b Add test for no-alias-deps import resolution bug
c3f0f46ee Update for dune 3.21
git-subtree-dir: odoc
git-subtree-split: 71fe7ccd36eee7f244a355653e10de197d6bcb94
- Widen sidebar from 200px to 260px with updated max-width calculations
- Collapse top two wrapper levels so content aligns with header
- Add border-left indentation guides on nested lists
- Replace original toggle arrows with larger inline chevrons (1em, rotate on expand)
- Separate click targets: chevrons toggle expand/collapse, links navigate
- Align childless items with toggle items via 20px margin-left
- Fix CSS cascade where .jon-shell-main ul overrode sidebar ul padding
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of requiring every .mld file to specify @x-ocaml.universe and
@x-ocaml.worker tags individually, configure the default universe path
once in dune-workspace (--config x-ocaml.universe=/_opam). The shell
emits <meta> tags from config values, and per-page @x-ocaml tags can
still override them.
Changes:
- dune-workspace: add --config x-ocaml.universe=/_opam to html_flags
- gen_rules.ml: pass --config to odoc html-generate for @site build
- odoc_jon_shell.ml: emit <meta> tags from x-ocaml.* config values
- odoc generator.ml: pass config to shell page_creator
- interactive_extension.ml: upsert meta tags (update existing or create)
- x_ocaml.ml: infer jtw backend from x-ocaml-universe meta tag
- Remove @x-ocaml.universe/@x-ocaml.worker from 14 .mld files using
the default /_opam universe
- deploy-site.sh: add dune install x-ocaml, chmod fix, widget-leaflet
- findlibish.ml: module detection fallback via jsoo runtime
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add new tessera-geotessera library with dune project structure, public
API (.mli), and grid math implementation (snap_to_grid, tiles_for_bbox,
tile_name, URL construction). Includes full implementations of
dequantize, mosaic, and fetch_mosaic_sync. Grid math tests all pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>