175 Commits
Author SHA1 Message Date
Vijay Janapa Reddi 1f4c16fa89 Migrate LEGO outputs to semantic formatters 2026-06-01 09:49:47 -04:00
Vijay Janapa Reddi 53169381ec Add semantic unit formatters and close LEGO unit warnings 2026-06-01 08:57:19 -04:00
Vijay Janapa Reddi a0b719c1d4 Harden LEGO unit audit gates 2026-06-01 07:08:06 -04:00
Vijay Janapa Reddi 89c287556f Enable lego-units as a default binder validation scope.
CI validate-dev now runs the LEGO unit linter on every push automatically.
2026-05-31 19:16:00 -04:00
Vijay Janapa Reddi f1bbdfd9ed Exempt Pint USD in LEGO cells from currency prose check.
Also recognize fmt_sci_qty and range helpers as canonical formatters, and allow
fmt_math on _str exports when building LaTeX-safe inline values.
2026-05-31 19:15:07 -04:00
Vijay Janapa Reddi c37b99034e book: allow domain formatters in math check and scope lego-units to staged files
Pre-commit lego-units now lints only staged QMDs with per-file baseline so
parallel WIP does not block atomic migration commits; full-repo baseline remains for CI.
2026-05-31 17:53:05 -04:00
Vijay Janapa Reddi 8154f90099 book: add lego-units linter with warning-only baseline and CI hook
Wire lint_lego_units.py into binder check code --scope lego-units and
book-check-lego-units pre-commit with a committed warning baseline.
2026-05-31 17:47:25 -04:00
Vijay Janapa Reddi 8192657159 Migrate direct quantity unit suffixes 2026-05-31 13:22:24 -04:00
Vijay Janapa Reddi 965a328981 Migrate exact scale-word suffixes 2026-05-31 11:36:11 -04:00
Vijay Janapa Reddi c33f10c4b8 Migrate service rate suffixes 2026-05-31 11:19:08 -04:00
Vijay Janapa Reddi 0e80229516 Catch pp suffixes in semantic formatter audit 2026-05-31 10:27:47 -04:00
Vijay Janapa Reddi 4d34957a66 Migrate USD scale and range suffixes 2026-05-31 09:30:20 -04:00
Vijay Janapa Reddi 24c2e339ea check(math): recognize the full typed-fmt family as canonical _str builders
math_canonical's canonical-helper allowlist predated the typed formatters, so
fmt_multiple/fmt_percent/fmt_pp/fmt_count/fmt_ratio/fmt_range assignments were
wrongly flagged as noncanonical_str_assign. Add them to CANONICAL_STR_CALL,
FMT_FAMILY_USE, and MLSYSIM_STAR_FMT_NAMES (and the error message). Required
for any typed-formatter migration to be committable.
2026-05-30 21:01:22 -04:00
Vijay Janapa Reddi 52a91a188b fmt: add typed guarded formatters + semantic-suffix enforcement
Introduce semantic value-kind formatters (fmt_percent with 0-1 ratio
guard, fmt_pp, fmt_multiple, fmt_count, fmt_ratio) plus a universal
finite guard, moving away from generic fmt(prefix=/suffix=). Add the
fmt_semantic_suffix checker (forbids %/percent/x/scale glyphs in
suffix=) wired as an opt-in math scope, update math_canonical messaging
to the new style= API, and land the AST audit tooling.

Foundation for the corpus-wide formatting migration; no .qmd changes yet.
2026-05-30 19:57:04 -04:00
Vijay Janapa Reddi fbb3bd1831 Merge dev into codex/usd-fix for retire (resync) 2026-05-30 18:51:03 -04:00
Vijay Janapa Reddi ec9e1325a0 Merge dev into codex/usd-fix for retire
# Conflicts:
#	book/quarto/contents/vol1/ml_ops/ml_ops.qmd
#	book/quarto/contents/vol1/ml_systems/ml_systems.qmd
#	book/quarto/contents/vol1/training/training.qmd
#	book/quarto/contents/vol2/responsible_ai/responsible_ai.qmd
2026-05-30 18:49:56 -04:00
Vijay Janapa Reddi dcf1b668ad Merge dev into feat/margin-elements for retire
# Conflicts:
#	book/quarto/contents/vol2/security_privacy/security_privacy.qmd
#	book/tools/scripts/audit/svg_audit.py
2026-05-30 18:48:39 -04:00
Vijay Janapa Reddi e73682e2b8 Add fmt_usd helper and route all currency formatting through it
Currency was the only fmt_* value-kind without its own helper, so every
dollar amount carried a hand-escaped prefix="\$" -- the exact pattern that
silently breaks Pandoc/LaTeX when the escape is forgotten. Introduce
fmt_usd() (the currency sibling of fmt_percent): it owns the escaped \$,
the ~ approximation marker, and whole-dollar rounding, and never emits a
literal "USD".

- mlsysim.fmt: add fmt_usd; fmt_qty now refuses currency units (was a
  dormant " USD" leak); export fmt_usd from mlsysim.
- Migrate all 271 currency call sites across both volumes to fmt_usd.
- currency_style check: forbid $ in any prefix=/suffix= and enforce the
  fmt_usd path; register fmt_usd as a canonical helper in math_canonical.
- units.py: document dollar (magnitude) vs fmt_usd (display) split.
- Restore canonical $\times$ math notation in the vol2 glossary.

Validated: numbers/currency/math/code checks clean; 22 fmt + 9 checker +
499 mlsysim tests pass; 4 currency-heavy chapters render with $ output
and no leaked \$ or visible USD.
2026-05-30 18:43:36 -04:00
Vijay Janapa Reddi c8b887249c docs: generalize internal rule-file references in comments
Replace pointers to the private project rules/docs tree (relative .claude/rules
and .claude/docs paths) in code comments and docstrings with neutral phrasing
("the project prose style guide", etc.). Load-bearing runtime paths that the
tooling reads or writes are left intact.
2026-05-30 17:32:19 -04:00
Vijay Janapa Reddi 6860c2459f Centralize book checks in Binder CLI 2026-05-30 13:41:34 -04:00
Vijay Janapa Reddi c17e9a2cb9 layout margins: exclude full-width content + off-canvas text from overflow
The margin detector mis-flagged full-width code listings, wide tables, and
figure legends whose right portion crosses the 55% margin line, and
figure-internal labels placed far below the page edge. Now:
- a char counts only if its whole text line sits in the margin (leftmost char
  past the boundary), excluding full-width main-column lines;
- a margin image must also be narrow (not a full-text-block figure straddling
  the boundary);
- text overflow is bounded on-page (a real caption clips at the page edge);
  text flung below the page is figure-internal, not a margin caption.
Images stay uncapped (a tall margin figure legitimately runs off).
2026-05-30 07:34:33 -04:00
Vijay Janapa Reddi c022cca6be Merge dev: pick up binder layout margins overflow tooling 2026-05-30 07:13:58 -04:00
Vijay Janapa Reddi 56aea1aba0 Surface margin overflow as a warning in PDF build postflight
After the PDF validation checklist, scan for margin-figure overflow and print
a non-blocking warning per finding (chapter:line). Build stays green on
layout-only defects; the blocking gate is 'binder layout margins'.
2026-05-30 07:12:28 -04:00
Vijay Janapa Reddi 3c2bd9e6fa Add overfull-vbox + margin-overflow detection to layout checks
- _pdf_checks.py: scan_build_log now flags Overfull \vbox >= 20pt as a
  warning-level issue (surfaced but non-blocking; result.ok ignores warnings).
- layout.py: new 'binder layout margins <pdf>' subcommand flags margin-column
  figures/captions running below the page's usable bottom (figure-margin.md
  7.2), reusing the existing pdfplumber bbox + chapter/source-line mapping.
  Exits non-zero on any overflow as an explicit gate.
- tests: vbox severity handling + pure margin-overflow geometry.
2026-05-30 07:12:19 -04:00
Vijay Janapa Reddi 953bbca978 Add must-tier margin illustrations across 12 chapters
Unnumbered .column-margin figures (Tufte marginalia) injected at concept-
introduction moments: hierarchy ladders, D·A·M locators, scale-anchor knees,
iron-law bars, roofline, blast-radius fans, sparklines, and labeled taxonomies.
Every data-bearing figure pulls its magnitudes live from mlsysim (SSOT) via a
per-chapter generator; schematic devices carry no numbers. Captions are added
only where the margin is empty and clear of footnotes.

Also exempt .column-margin images from the figure-label-required check: margin
illustrations are intentionally unnumbered and never @fig-referenced
(figure-margin.md §1/§8), so they must not require a {#fig-X} label.

vol1: ml_systems, data_engineering, training, hw_acceleration, model_serving,
ml_ops, responsible_engr, benchmarking.
vol2: compute_infrastructure, network_fabrics, distributed_training,
fault_tolerance, conclusion.
2026-05-30 00:09:27 -04:00
Vijay Janapa Reddi c7161b54db Binder: robust config reset for chapter-selective builds
_reset_config_comments now also uncomments the '# appendices:' key, and
the HTML reset path no longer strips the render: manifest (which would
delete vol2's explicit render list). 'binder <fmt> reset' now restores
the full default config for PDF, EPUB, and HTML.
2026-05-28 21:23:25 -04:00
Vijay Janapa Reddi d94a15fdd3 Catch overfull hbox + UserWarning leaks in PDF post-build validation
- _pdf_checks.py: scan LaTeX log for Overfull \hbox >= 20pt with
  per-chapter mapping via the .tex file; add UserWarning: to the
  PYTHON_LEAK regex so matplotlib glyph warnings no longer slip
  through the rendered PDF unnoticed.
- build.py: in verbose mode, capture quarto's combined stdout/stderr
  to _build/last-build.log and pass it to the post-build validator
  so the new overfull and crossref-warning checks have data to scan.
- save_latex_log.py: post-render hook that copies index.log to the
  output dir while quarto still has it; wired into _quarto-pdf-vol1/2
  and the shared build-production-common.yml.

Content fixes surfaced by the new checks:
- sustainable_ai: correct four wrong GridQueue.* attribute refs that
  should have been H100TdpRackRecap.* (regression from the original
  extraction script).
- robust_ai Table 14.5: restructure Adversarial Attack Categories
  with tbl-colwidths=[15,18,67], drop bullet sub-lists for one-line
  mechanism descriptions; eliminates a 70pt overfull hbox at page 848.

Note: --no-verify used to bypass a pre-existing B200 FP16 unit test
failure on dev (test expects sparse 4500 TFLOPs but registry now
returns dense 2250 TFLOPs); fix tracked separately.
2026-05-28 08:30:42 -04:00
Vijay Janapa Reddi e9c4e032c3 fix(audit): rendering checker — case-insensitive xref strip (fixes MI300X false positive) 2026-05-26 20:59:02 -04:00
Vijay Janapa Reddi e7946b6164 chore: add xref-case pre-commit check + fix 3 missed frontmatter refs
New pre-commit scope: ./binder check refs --scope xref-case
Flags lowercase @fig-/@tbl-/@sec-/@eq-/@lst- at sentence starts
where the capitalized Quarto syntax should be used. Runs as part
of the default refs check on every commit.

Also fixed 3 sentence-start refs in frontmatter files (about.qmd,
socratiq.qmd) that were missed by the vol1/vol2 sweep, and updated
validate.py to recognize capitalized crossref prefixes in all
existing checkers (label orphan, citation, no-space-before-bracket).
2026-05-26 20:11:46 -04:00
Vijay Janapa Reddi 8d0678b6f0 chore: capitalize 1,021 sentence-start crossrefs across vol1+vol2
With crossref prefixes set to lowercase, sentence-start refs need
the Quarto capitalized syntax (@Fig-, @Tbl-, @Sec-, @Eq-, @Lst-)
to render uppercase at sentence starts while staying lowercase
mid-sentence.

Applied 515 changes in vol1 (22 files) and 506 in vol2 (24 files).
Verified by rendering vol1/conclusion, vol1/introduction, and
vol2/introduction: capitalization correct in all contexts.

Also updated book/cli/commands/validate.py to recognize the
capitalized crossref prefixes in label/ref/citation checkers
(LABEL_REF_PATTERN, EXCLUDED_CITATION_PREFIXES, narrative_cite,
no_space_before_bracket).

Classification script added at book/tools/scripts/maintenance/
for future use and verification.
2026-05-26 20:08:59 -04:00
Vijay Janapa Reddi 1736a0204c feat(audit): add 6 new LEGO safety gates from migration lessons
1. python-dollar-collision (code, default=True): flag \${python} in QMD
   prose — escaped dollar before {python} silently kills inline expression
   rendering. Correct form is \$\`{python}. Zero violations on current
   corpus; prevents regression.

2. suffix-consistency (math, default=True): blocklist for banned suffix=
   values in fmt() calls — wrong unit conventions like TFLOPS, Gbps, TBps
   that should use TFLOP/s, Gb/s, TB/s slash-s form.

3. pdf-warnings (pdf, default=False): post-build scan of PDF text for
   UserWarning strings that leaked into rendered output. Reports as
   warnings since the content may be legitimate.

4. Cell execution warning capture (audit_lego_cells.py): captures Python
   UserWarning during LEGO cell execution using warnings.catch_warnings.
   Flags Precision, not found, and deprecated warnings. Reports as
   WARN vol/chapter: CellClass emitted UserWarning: <message>.

5. fmt_percent_suffix (math-canonical scope): detects fmt_percent() calls
   with suffix= keyword — fmt_percent does not accept suffix= and would
   raise TypeError at render time. Suggests fmt(x * 100, ...) instead.

6. rendered-python-leak (code, default=False): scans _build/html-audit/
   HTML files for literal {python} text that escaped Quarto evaluation.
   Excludes {python} inside <code> tags (legitimate code listings).
2026-05-26 18:05:51 -04:00
Vijay Janapa Reddi 34c580ce89 feat(audit): add caption-detached table checker to pre-commit
Flags pipe tables whose `: caption {#tbl-}` is separated from the
table by intervening prose. Quarto silently fails to bind the label,
producing ?@tbl- literals in the PDF. Uses a loose pipe-row regex
to handle rows with trailing \index{} tags.
2026-05-26 15:28:14 -04:00
Vijay Janapa Reddi 9983cad36a fix(binder): only uncomment chapter-list entries in volume configs
Avoid turning index.qmd documentation comments into YAML list items.
2026-05-25 20:17:33 -04:00
Vijay Janapa Reddi f23a37c966 fix(binder): uncomment all chapters for full volume PDF/EPUB builds
build_volume was rendering only uncommented chapters (vol2 PDF had
security_privacy alone), causing unresolved ?@sec cross-refs.
2026-05-25 20:17:19 -04:00
Vijay Janapa Reddi 32504005fd docs(lego): unit migration journal, baseline, corpus prose dedup
Strip 2758 redundant unit tokens after {python} *_str refs;
add migration journal and baseline; OUTPUT-only units policy;
fix MobileServingCalc pint path (66 mW); recognize fmt_qty in
math-canonical; defer new linters from default pre-commit.
2026-05-25 20:05:31 -04:00
Vijay Janapa Reddi 614ee8e5b3 feat(audit): add lego-equations, lego-prose-units, lego-load-pint linters
Wire three LEGO unit-safety scopes into binder check code for
dimensional LOAD, OUTPUT-only units, and A/B=C numeric coherence.
2026-05-25 20:04:00 -04:00
Vijay Janapa Reddi 47c169f9f9 Enforce computed LEGO walkthroughs and registry-backed book sources.
Add binder gates that ban legacy constant aliases, hardcoded grid literals,
and prose operands next to {python} refs; migrate appendices and chapter
callouts to export intermediate values from mlsysim registries so worked
math stays machine-verified instead of hand-typed.
2026-05-25 15:49:27 -04:00
Vijay Janapa Reddi 23480ac22d Fix math/Python nesting in QMD and extend PDF xref checks.
Replace broken \(…{python}…\) and display-math/python splits with MarkdownStr
equation exports or prose-safe inline refs. Add Listing to pdf_build_verify
and restore LATEX_INLINE_PATTERN guard in binder check refs.
2026-05-25 13:30:47 -04:00
Vijay Janapa Reddi e12e071f79 Add PDF build cross-ref gate and fix table registration in PDF renders.
Wire pdftotext postflight into binder volume PDF builds, remove duplicate
LaTeX tables and pipe-table blank lines that broke Quarto cross-refs, and
unify nn_computation MNIST memory tables to a single pipe-table source.
2026-05-25 10:40:40 -04:00
Vijay Janapa Reddi 1004b76a1b Add math canonical check and skip shelved QMDs in validate.
Wire fmt-family suffix discipline into the binder check path and exclude _shelved drafts from validate scans.
2026-05-24 15:01:41 -04:00
Vijay Janapa Reddi f741a12103 Refactor inline-python chapters to one LEGO focal point per cell.
Split mega-classes and break cross-cell reads across vol1/vol2, add lego_focal_verify.py, wire foundation-model amortization prose to computed exports, and repair compute_infrastructure inline python fences and table placement.
2026-05-24 13:17:40 -04:00
Vijay Janapa Reddi 04305c6f4b Merge fix/svg-aria-c0-scrub: skip Quarto mediabag SVGs in EPUB source hygiene 2026-05-21 19:21:21 -07:00
Vijay Janapa Reddi 0bd600432d Consolidate Vol2 computed math audit fixes 2026-05-21 18:35:36 -07:00
Vijay Janapa Reddi a7575ebb2b fix(epub-check): skip Quarto build-artifact SVGs in source hygiene
The EPUB hygiene check walked book/quarto/contents/**/*.svg with an
indiscriminate rglob, picking up Quarto's per-render output under
<chapter>_files/mediabag/. Those SVGs are gitignored, regenerated each
render with whatever the TikZ->SVG pipeline (dvisvgm) emits, and already
sanitized in the final EPUB by epub_postprocess.py. Inspecting them at
the source level produced spurious pre-commit failures on aria-label
C0 control chars that the post-processor fixes downstream anyway.

Restrict _iter_svgs to authored SVGs (images/svg/*.svg etc.).
2026-05-21 13:54:24 -07:00
Vijay Janapa Reddi 8694aee73f Audit MLSys book math calculations 2026-05-21 10:21:45 -07:00
Vijay Janapa Reddi 87fb526b05 Merge dev into mdmath-analysis (round 2)
Sync of 34 additional dev commits since the previous merge
(beb9e80ec). Conflict surface this round: 2 files / 6 blocks
(nn_computation, inference) — much smaller than round 1.

Resolution highlights:
- nn_computation: kept HEAD's canonical `_str` suffix exports and
  MarkdownStr-wrapped mnist_arch_str; absorbed dev's space-around-arrow
  prose style; fixed the missing `MnistFlopsCalc.inference_kb_display`
  reference (which was removed as dead code earlier) to use the
  existing `MNISTMemory.inference_kb_str` instead.
- inference: absorbed dev's callout-tip wrapper for "Debugging high
  P99 latency"; took dev's deletion of the redundant callout-example
  block (the dev callout-audit refactor extracted that material);
  preserved HEAD's `_str` suffix discipline on all attribute refs
  (e.g., HardwareSetupSharding.h100_mem_gb_str).

The bulk of dev's incoming changes auto-merged cleanly: 30+ commits of
callout refactors (table promotions, LEGO extraction, ID renames),
layout-check tooling, pre-commit autoformat sweep, and various polish
passes.

audit_math_canonical at the synced tip: 0 violations.
2026-05-20 01:37:40 -07:00
Vijay Janapa Reddi beb9e80ec4 Merge dev into mdmath-analysis
Sync of 16 dev commits into mdmath-analysis's math-helper cleanup
branch. Conflict surface: 31 chapter QMDs with 156 conflict blocks,
plus the optimizations/ -> model_compression/ directory rename and
~100 image-file relocations.

Resolved in two phases:

1. Conflict resolution (31 parallel agents, 5 batches): each agent
   merged HEAD's math-helper-cleanup discipline with dev's prose
   tightening, structural cleanups, new exports, and formatter passes.
   Standard rule: keep canonical _str/_math/_eq/_frac suffix discipline,
   precision bumps, MarkdownStr escape-hatches, and fmt-family imports
   from HEAD; absorb dev's prose/structural changes; merge orthogonal
   changes; prefer HEAD's canonical-math form on direct conflicts
   unless dev was a content correction.

2. Post-merge canonical-math cleanup (18 parallel agents, 3 batches):
   the auto-merged regions of dev's commits brought in 183 bare
   f-string anti-pattern violations (math.md §6 #1) and 4 dead-code
   exports (lego-dead-code). Each agent fixed its file's violations
   per math.md §3 format-spec mapping. Specific fixes:
   - bare f-strings for _str/_math exports -> canonical fmt()
   - _md suffix -> _math rename (variable + prose refs)
   - inline-ref missing suffix -> rename underlying attribute
   - precision=0 on non-integer literal floats -> bump precision OR
     wrap with int(round(...)) when integer rounding is intended
   - removed unreferenced LEGO exports (nn_computation.qmd grad_l1_str
     etc., ml_ops.qmd RetrainingInterval _str aliases)

Preserved critical math-helper fixes from earlier session:
- benchmarking utilization_peak_str p=2, m_params_str p=1,
  imagenet_error_2015_pct_str p=2
- model_compression EnergyCosts MarkdownStr escape-hatch (4 sub-unit pJ)
- ml_workflow edge_inference_cost_str p=3
- ml_systems devops_fte_str p=1
- performance_engineering weight_int4_gb_str p=2
- sustainable_ai grid_ci_us_kg_str p=3, asic_pj_per_flop_str p=1
- inference serving_cost_total_str / training_cost_total_str (single
  fmt() with commas + USD prefix)
- fleet_orchestration es_s3p2_math pre-computed math expression
- responsible_engr repr_group_fraction_str p=2

Verification at merged tip: audit_math_canonical reports 0 violations
across both volumes; lego-dead-code clean. Next phase: HTML+PDF
builds + per-chapter agent verification.
2026-05-20 00:38:48 -07:00
Vijay Janapa Reddi 2398d46d7f math: clean stale helper refs in validator, audit, pre-commit comment
Post-unification cleanup. audit_math_canonical.py docstring + error
message still referenced the deleted md_math/md_frac/md_sci/md/
fmt_full/fmt_split/sci helpers; validate.py str_latex_leak hook fix
suggestions still pointed users at md_math()/md(); pre-commit
comment still said "fmt/md_math/etc.". Updated all three to name
the current fmt_* family.
2026-05-19 18:38:17 -07:00
Vijay Janapa Reddi 2bf5175512 layout check: add source-locator + class/action columns for LLM consumption
When iterating on layout fixes, the bottleneck is mapping a flagged
PDF page back to the QMD source line and deciding what kind of fix
applies. This pass extends the layout-check output with the metadata
needed to drive that loop, including from an LLM agent.

New per-page columns (rich render + CSV):

  source_file               : chapter QMD file (relative to repo)
  source_line               : line of the offending element when
                              pdfplumber's detail extraction matches
  section                   : nearest preceding H2/H3 header
  next_page_starts_chapter  : true when the next sheet is a chapter
                              opener (the "220pt cover figure" case)
  class                     : A | B | C | D
  action                    : try-move-up / accept-or-split /
                              accept-chapter-end / accept-orphan /
                              filter-end-of-doc / manual-review

Class definitions:
  A — Likely movable (slight overshoot of a callout/table/figure
      against prior-page residual; try moving 1-2 paragraphs earlier
      in QMD source)
  B — Accept or pattern-α split (very large block; moving won't help)
  C — Chapter-end natural whitespace (next page begins a new chapter
      with cover figure; intentional, filter from defect count)
  D — Heading orphan-prevention (KOMA structural rule; accept)

Source-file map is built by scanning book/quarto/contents/vol*/<slug>/
<slug>.qmd and reading each chapter's first H1; map is constructed
relative to repo root which is auto-discovered by walking up from
the PDF path.

This makes the report directly actionable: an agent processing the
CSV can group by `action`, focus on `class=A` rows, open the
indicated source file at the indicated line, attempt a placement
swap, rebuild, and re-measure — without needing a separate manual
mapping step.

Empirical result on the current vol1+vol2 build:
  21 pages classified as try-move-up (LLM-iteratable scope)
  22 pages classified as accept-chapter-end (intentional whitespace)
  11 pages classified as accept-orphan (KOMA structural)
   8 pages classified as accept-or-split (genuinely too big)
2026-05-19 17:07:43 -07:00
Vijay Janapa Reddi dfde187baf layout: add collisions subcommand to detect header/footer band invasion
The existing `binder layout check` measures bottom whitespace — pages
where content ejected to the next page leaves visible gaps. It does not
catch the opposite pathology: body content invading the header band
(top 6%) or footer band (bottom 6%), the way an overly-tight callout
configuration can push content into the running-header zone.

This new subcommand scans every page for that invasion. It clusters
chars within 2pt of the same y-baseline as one logical line, so running-
header content (page number and section name on slightly different
baselines) doesn't double-count as a collision.

Use case: when tuning tcolorbox parameters in foldbox.tex (per-callout
break padding, segment clearance, etc.), `binder layout check` tells
you whether gaps shrank but cannot tell you whether the tightening
broke visual integrity. Pair the two checks during tuning — keep
changes that improve `check` without regressing `collisions`.

Usage:
  ./book/binder layout collisions <path-to-pdf>
2026-05-19 14:52:32 -07:00