220 Commits

Author SHA1 Message Date
Vijay Janapa Reddi
82b7679c3d Add end-of-chapter research questions 2026-07-01 12:23:48 -04:00
Vijay Janapa Reddi
70a6ec5f84 feat(binder): add markdown list-spacing check for bold lead-ins
A bold lead-in paragraph (e.g. **Step 2**: ...) immediately followed by a
list item with no blank line between them is parsed by Pandoc as one
paragraph, so the list marker can render inline. Add a markup check
(check markup --scope list-spacing) that flags this, extend the
format lists fixer to insert the blank line for bold lead-ins (not just
colon-terminated lead-ins), and cover both with tests.
2026-06-28 21:54:40 -04:00
Vijay Janapa Reddi
886e58a307 Refine Binder release gate classification 2026-06-20 20:52:22 -04:00
Vijay Janapa Reddi
f127d268fa Rename Binder release workflow 2026-06-20 18:12:35 -04:00
Vijay Janapa Reddi
9e265ef700 Add Binder pre-release workflow 2026-06-20 16:59:53 -04:00
Vijay Janapa Reddi
d02c5e8aaf Fix margin offset handling in PDF output 2026-06-20 12:32:52 -04:00
Vijay Janapa Reddi
d539b78da5 test(binder): fix footnote cross-chapter false positives 2026-06-19 09:39:46 -04:00
Vijay Janapa Reddi
b54b63e140 fix(pdf): harden rendered validation gates 2026-06-19 08:11:51 -04:00
Vijay Janapa Reddi
5e95ebb9aa Enforce bottom pipe table captions 2026-06-18 06:57:53 -04:00
Vijay Janapa Reddi
c848f43990 layout: wire Purpose-overflow check into binder layout
Adds 'binder layout purpose <pdf> --vol1|--vol2' subcommand and folds the
check into the high-level 'binder layout --vol1/--vol2' planner so a Purpose
spilling past its opener page is caught with the other layout scans and fails
the layout pass. Delegates to book/tools/audit/check_purpose_overflow.py.
2026-06-17 09:07:09 -04:00
Vijay Janapa Reddi
be3992e0f9 fix(bib): links check retries GET on HEAD 404/403/405
Some servers and doi.org (DataCite DOIs, e.g. NIST) answer HEAD with 404 but
GET with 200. Retry GET before declaring a locator dead. Cuts false positives
from 33 to 17 true dead 404s; timeouts/DNS now warn (could-not-confirm) rather
than error.
2026-06-15 09:28:37 -04:00
Vijay Janapa Reddi
c3dff7ecdc feat(bib): native DOI/URL liveness check (opt-in 'links' scope)
binder check bib --scope links resolves every doi/url in the shared bib
(MIT Press: confirm all URLs). HTTP 404/410 = error (dead); timeout/DNS/5xx
= warning (could-not-confirm); 403/401 = warning (bot-block). Network-bound,
default=False so it is not a pre-commit gate. Found 21 dead 404 locators.
2026-06-15 09:22:34 -04:00
Vijay Janapa Reddi
81b97abaf3 feat(bib): native pre-commit gates for key-year drift + duplicate keys
Two new default-on, errors-only bib check scopes (native in Binder):
- key-year: key year vs entry year (>1yr gap = silent citation corruption).
  Errors-only subset of key-content, so the intentional surname WARNINGs stay
  opt-in and do not block commits. Skips standards-numbered keys.
- duplicate-keys: every citekey must be unique (bibtex-tidy only warned;
  the openai2023gpt4 collision slipped through). Both auto-join the curated
  'binder check bib' set -> wired to the book-check-bib pre-commit hook.
2026-06-15 09:17:19 -04:00
Vijay Janapa Reddi
d02a5d4856 fix(bib): skip standards-numbered keys in key-content check
The key-content regex ^([a-z]+)(\d{4}) read the first 4 digits of a standard
number as the entry year (iso14040 -> 1404), firing 5 false-positive ERRORs on
ISO/IEC/IEEE/NIST entries. Add a STANDARDS_KEY_PREFIXES skip. Verified it skips
exactly 7 genuine standards entries and no real author.
2026-06-15 08:49:03 -04:00
Vijay Janapa Reddi
d7c8a82a77 Merge branch 'dev' into chore/betterbib-june
# Conflicts:
#	book/quarto/contents/vol1/benchmarking/benchmarking.qmd
#	book/quarto/contents/vol1/conclusion/conclusion.qmd
#	book/quarto/contents/vol1/data_engineering/data_engineering.qmd
#	book/quarto/contents/vol1/introduction/introduction.qmd
#	book/quarto/contents/vol1/model_serving/model_serving.qmd
#	book/quarto/contents/vol1/nn_architectures/nn_architectures.qmd
#	book/quarto/contents/vol2/collective_communication/collective_communication.qmd
#	book/quarto/contents/vol2/network_fabrics/network_fabrics.qmd
#	book/quarto/contents/vol2/sustainable_ai/sustainable_ai.qmd
2026-06-14 19:52:18 -04:00
Vijay Janapa Reddi
45aeb6b026 Audit citations and consolidate bibliography 2026-06-14 19:41:26 -04:00
Vijay Janapa Reddi
2f72d12ad0 Add v03 chapter cover assets 2026-06-13 17:30:34 -04:00
Vijay Janapa Reddi
9f9c0d889b Fix inline Python math validation 2026-06-13 14:00:34 -04:00
Vijay Janapa Reddi
323081aa38 Fix layout CLI Python compatibility 2026-06-12 13:00:37 -04:00
Vijay Janapa Reddi
efab848914 layout: add two-phase auto layout planner 2026-06-11 20:55:44 -04:00
Vijay Janapa Reddi
bd40d3950f Merge branch 'dev' into feat/auto-margin-layout 2026-06-11 16:12:53 -04:00
Vijay Janapa Reddi
c6d214fe80 chore(audit): remove local MIT Press path assumptions 2026-06-11 16:09:10 -04:00
Vijay Janapa Reddi
92f9165d03 fix(book): harden LEGO formatting across volumes
Add native Binder checks for LEGO formatting/unit/prose contracts, extend mlsysim formatter helpers, and normalize Vol1/Vol2 LEGO output strings through typed formatters.

Validate precision-sensitive prose rendering across both volumes and promote direct math/string assembly to fmt_math, fmt_display_math, fmt_text, and domain-specific helpers.
2026-06-11 14:36:35 -04:00
Vijay Janapa Reddi
41beff5863 Keep constraint-response war-stories on a Resolution beat
Five war-stories (PaLM loss spikes, AlexNet two-GPU split, Google TPU,
Discord Rust rewrite, Facebook inference tax) have a third beat that is
the engineering *response* to the constraint, not the damage from a
disaster. Folding that fix into Failure mode buried the most useful beat
for a student (what the engineers actually did) and the book's core move
(a constraint forcing an architecture). Restore it as a distinct
**Resolution** beat. Disaster war-stories, whose third beat is damage,
stay folded to Context / Failure mode / Systems lesson.

Teach the callout-schema check to accept both war-story archetypes:
Context / Failure mode / Systems lesson, or with an optional Resolution.
2026-06-11 09:41:00 -04:00
Vijay Janapa Reddi
dd3e6cb9c1 Add binder-native callout-schema consistency check
New 'markup --scope callout-schema' enforces a uniform bold-label
structure per callout type: every .callout-war-story must be
Context / Failure mode / Systems lesson and every .callout-definition a
single triple-bold term head. Runs in pre-commit and *-validate-dev CI
like the sibling 'callouts' scope. Registered default=False until vol2
narrative callouts are normalized to the same schema (17 still flagged
there); vol1 passes clean.
2026-06-11 09:31:07 -04:00
Vijay Janapa Reddi
d79b806870 feat(binder): enforce that book-content hooks dispatch through Binder
Adds 'binder check cli --scope binder-canonical' (default=yes): parses
.pre-commit-config.yaml and fails if any local hook scoped to book/quarto/
contents/ calls a raw script instead of ./book/binder. Repo-wide guards, CI
hygiene, third-party hooks, and other subprojects are not book content and
are not inspected; an explicit ALLOWLIST covers any justified exception.

This makes Binder-as-single-front-door a mechanically enforced invariant
instead of a convention — the day someone wires an off-Binder book hook (as
book-check-lego-units once was), the commit fails with an actionable fix.
Runs via the existing always-run book-check-cli-contract hook; no new hook.

Also hardens the cli-contract 'check cli help' case to assert on stable
tokens (group header + scope names) rather than the note phrase, which Rich
wraps once a group gains a scope. Extends it to cover the new scope.
2026-06-10 17:22:46 -04:00
Vijay Janapa Reddi
6fd3171eff fix(book): add GPUDirect, GoogLeNet, MLflow to heading-case proper nouns
These §10.7 proper nouns must stay capitalized in sentence-style headings
(§10.3.1). Without them, heading-case lowercased 'GPUDirect' → 'gpudirect',
conflicting with the spelling-dict check that capitalizes it. Adds them to the
ACRONYMS preserve-set so the two MIT Press checks agree.
2026-06-10 14:18:39 -04:00
Vijay Janapa Reddi
cd06d697b7 feat(book): mitpress-spelling-dict check + mitpress-terms auto-fixer (§10.7) 2026-06-10 14:13:10 -04:00
Vijay Janapa Reddi
ff0a1ed1ab refactor(book): graduate 4 more checks to _run_mitpress_ prefix
These enforce MIT Press copyedit / style-sheet rules but were not labeled:
  _run_caption_head_style -> _run_mitpress_caption_head_style  (sentence-style caption/box heads, bold-head format)
  _run_heading_case       -> _run_mitpress_heading_case        (headline 1-2 / sentence 3+ heads, §10.3.1)
  _run_contractions       -> _run_mitpress_contractions        (§10.11 forbidden in body prose)
  _run_alt_text_style     -> _run_mitpress_alt_text_style      (§10.12 alt-text body-prose rules)

Scope names (CLI surface) unchanged; only method identifiers move, so
pre-commit, CI, and the CLI contract are unaffected.
2026-06-10 14:01:20 -04:00
Vijay Janapa Reddi
d0f0fcedf6 feat(book): contractions check — exact-expansion suggestion + quoted-speech exemption
Body prose forbids contractions as a deliberate register override of the copy
editor's permissive default (mit-press-editorial.md §10.11). Two improvements:

- LLM-actionable: emit suggestion '<contraction> → <full form>' from an
  expansion map (can't → cannot, it's → it is, …), case-preserving at sentence
  start.
- §10.11 exception: mask inline code and double-quoted spans before matching so
  contractions in quoted speech / direct dialogue are not flagged.
2026-06-10 13:53:29 -04:00
Vijay Janapa Reddi
730ce4b885 feat(book): make percent-check output LLM-actionable (exact suggestion)
Automated fixers consume 'binder check <group> --json', so every issue must
carry the exact fix. Populate ValidationIssue.suggestion as '<wrong> → <right>'
for both percent checks:
  - percent_in_table: '50 percent → 50%'
  - percent_in_prose: '98.5% → 98.5 percent'; range hits get a judgment note
    ('30–50% → (range) X to Y percent') instead of a misleading per-value fix.

percent_prose.Hit now carries an explicit replacement + is_range flag.
Documented the contract (file/line/code/suggestion/context) in the
ValidateCommand 'adding a check' docstring so future checks inherit it.
2026-06-10 13:43:42 -04:00
Vijay Janapa Reddi
1fbd6f11ac refactor(book): mark MIT-Press-originated checks with _run_mitpress_ prefix
The _run_mitpress_* prefix already marks checks that trace to the MIT Press
copyedit (em-dash, slash, vs., e.g./i.e., percent-in-captions, etc.). Extend
it to six more that derive from the copy editor's style sheet / AU query
categories but were not yet labeled, so provenance is visible in the check
registry:

  _run_abbreviation_first_use      -> _run_mitpress_abbreviation_first_use   (Cat F + abbrev list)
  _run_concept_term_capitalization -> _run_mitpress_concept_term_capitalization (Cat G + glossary cap)
  _run_percent_in_prose            -> _run_mitpress_percent_in_prose         (style sheet: spell out %)
  _run_percent_in_tables           -> _run_mitpress_percent_in_tables        (style sheet: % kept in tables)
  _run_latin_running_text          -> _run_mitpress_latin_running_text       (spell out e.g./i.e./viz.)
  _run_compound_prefix             -> _run_mitpress_compound_prefix          (close up non-/re-/pre-)

Scope names (CLI surface) are unchanged, so pre-commit, CI, and the CLI
contract are unaffected; only the internal method identifiers move.
2026-06-10 13:36:03 -04:00
Vijay Janapa Reddi
73865fd116 feat(book): add percent-in-prose check
New 'percent-in-prose' scope (numbers group, default=True) flags the %
symbol where body prose should spell out 'percent', the symmetric inverse of
percent-in-tables. Per MIT Press AU response Category H / Chicago §9.18,
running prose (body, caption sentences, alt text) uses the word; % is for
tables, equations, code, and in-figure data.

Detection (cli/checks/percent_prose.py) reuses the pipe-table walk to exclude
tables and exempts every legitimate non-prose context: code, math, Quarto
attributes ({width=100%}), link/image targets and URLs, <style> CSS, HTML
comments, caption/alt lines, and quoted material (a % inside double quotes is
a verbatim quotation). No auto-fixer: prose ranges need judgment.
2026-06-10 13:22:28 -04:00
Vijay Janapa Reddi
979ca523c6 feat(book): native percent-in-tables check + format target
Tables invert the prose convention and use the % symbol, not the word
'percent'. This adds enforcement on both sides, sharing one implementation
in cli/checks/percent_tables.py (matching the cli/checks/currency_style.py
pattern) so the fixer fixes exactly what the check flags:

- check:  'percent-in-tables' scope in the numbers group (validate.py),
          default=True → runs in book-check-numbers pre-commit + validate-dev
          CI automatically.
- fix:    native 'percent-tables' target in the format command
          (./book/binder format percent-tables), wired as the
          book-format-percent-tables pre-commit hook ahead of prettify so
          columns realign after the substitution shortens cells.

Detection reuses the header+separator pipe-table walk shared by the other
table checks, gated by a number-token before 'percent' so header labels and
'percentage points / pp' are never touched.
2026-06-10 13:10:32 -04:00
Vijay Janapa Reddi
8af8707963 binder: wire the margin-geometry oracle into layout + build validation
Adds 'binder layout overlaps <pdf>': a true-geometry PyMuPDF scan for
element-on-element margin overlaps and footer/header overflow that the
anchor-based 'margins' scan is blind to. Exits non-zero on any overlap
(always a bug); --strict also gates on overflow.

Also wires the same scan into verify_volume_pdf as a non-blocking warning,
so every validated PDF build reports 'Margin geometry: N overlaps, M
overflow'. Gracefully skips when PyMuPDF is absent (e.g. minimal CI).
2026-06-09 16:23:53 -04:00
Vijay Janapa Reddi
3037fa2d1d feat(layout): suggested_fix column for binder layout margins --csv
Each margin overflow now ships a ready-to-apply recipe: the computed
in-block \vspace*{-Xmm} nudge (seed = ceil(over_pts*0.45)+2 mm, where
0.45 pre-absorbs the ~18% a \vspace* loses inside a marginnote), the
resolved .column-margin block addressed by SVG/PNG asset name and line
(robust against the scanner's prose-line mis-anchoring), or a footnote
[offset], or "needs eyes" when no block sits near (body table / mis-
anchored). Realizes the computable half of auto-layout.md §2.4 inside
binder so the figure-overflow sweep stops being hand-measured.

Additive: appends one CSV column, no flag/contract change.
2026-06-09 07:32:36 -04:00
Vijay Janapa Reddi
14751a2042 feat: add percent-word-before check and fix two corpus violations
New binder check 'numbers --scope percent-word-before' flags spelled-out
number words before 'percent' (e.g. 'five percent' -> '5 percent').
Rule: 'percent' acts as a unit; digits always per numbers-and-math-in-prose.md.

Also fix two pre-existing violations:
- nn_architectures.qmd: 'ten percent' -> '10 percent'
- robust_ai.qmd: 'one percent' -> '1 percent'
2026-06-08 20:25:51 -04:00
Vijay Janapa Reddi
f24bd48672 Unify the C3 axis name on Compute
The book split on the first axis's name: the vol2 introduction's
formal definition list, the C3 diagnostic appendix, the DAM
projection, the fleet quick-reference, and quizzes said 'Computation
(C1)' while the c3-taxonomy figure, the part principles, the
displacement-of-overhead invariant, and all prose triads (4:0) said
'Compute'. Unified on Compute everywhere the word names the axis
(~30 sites), including index subentries (!computation -> !compute),
the Compute-bound regime label, and the MFU underbrace. Generic uses
(prefill computation, Communication-Computation overlap/ratio, SMPC,
MoE stage labels, code identifiers) untouched; anchors unchanged.
Both heading-case checkers' axis allowlists learn 'Compute' so the
'(Compute)' case-study heading label passes as a framework label.
2026-06-07 20:27:15 -04:00
Vijay Janapa Reddi
842091f6a8 Merge dev into feat/algorithm-pseudocode for retire 2026-06-06 12:37:40 -04:00
Vijay Janapa Reddi
af79ff3edd Add formal algorithm blocks and the pseudocode extension that renders them
Introduce 13 LaTeX-typeset algorithm blocks across 8 chapters (Adam update,
gradient checkpointing, FlashAttention, backpropagation, mini-batch SGD,
reverse-mode AD, PTQ calibration, tiled GEMM, ring all-reduce, 1F1B pipeline,
continuous-batching scheduler, speculative decoding, power-of-two routing),
each integrated into existing prose with a motivating lead-in and a
systems-consequence follow-up.

Extension (book/quarto/_extensions/mlsysbook-ext/pseudocode):
- Vendored under the owned mlsysbook-ext/ namespace (moved from leovan/,
  version -mlsysbook-custom) and wired into the html, pdf, and epub filters.
- MIT Press cross-ref casing: @algo- -> 'algorithm N' mid-sentence,
  @Algo- -> 'Algorithm N' at sentence start.
- Right-aligned italic triangle comments (CLRS column convention).
- Static EPUB renderer (upstream supports only HTML via pseudocode.js and PDF
  via algpseudocodex; EPUB previously emitted raw \begin{algorithm}).
- Uses the algo- prefix: native @alg- collides with Quarto's algorithm theorem
  environment and FATALs the build.

Ref tooling (book/cli/commands): teach validate.py, bib.py, and info.py the
algo-/Algo- crossref prefix (LABEL_REF_PATTERN, EXCLUDED_CITATION_PREFIXES,
Algorithm label-def patterns, and a chunk-option label harvest that runs inside
the pseudocode fence) so check refs and check labels resolve @algo-/@Algo-
instead of misreading them as missing citations.

Verified rendering in HTML, PDF, and EPUB; check refs and check labels pass
book-wide.
2026-06-06 12:36:17 -04:00
Vijay Janapa Reddi
5b34d89c64 Merge dev into fix/lego-cell-format for retire
Resolved 36 conflicts by taking dev's side (mlsysim-deferred-polish
import migrations) and deterministically re-applying this branch's
mechanical transformations: LEGO cell reformat, dead #| label removal,
and the two #| output: false hoists.
2026-06-06 12:07:52 -04:00
Vijay Janapa Reddi
7c9f85fa5d Make blanks formatter fence tracking ignore HTML comments
_collapse_blank_lines toggled code-block state on every ``` line,
but commented-out figures (<!-- ... -->) often contain partial code
blocks with unbalanced fences. One stray fence inverted the toggle for
the rest of the file, so real python cells were treated as prose and
their blank lines collapsed (observed in security_privacy.qmd, which
desynced at its first commented-out tikz block).

Skip fence tracking and blank collapsing inside HTML comment regions;
commented-out content passes through verbatim.
2026-06-06 11:47:26 -04:00
Vijay Janapa Reddi
9c3dce60dc Delete the core/constants.py compat shim; migrate the whole corpus
No-backward-compat sweep, part 2. The module had been reduced to a
units-only re-export ('retired, do not add values'); per policy it is
now gone and every consumer reads the real home:

- 32 internal modules, the package __init__, and core/__init__ import
  core.units (physics modules keep their own physics/constants)
- 43 book chapters' LEGO cells migrated (star imports, named imports,
  and the appendix attribute style 'constants.VIDEO_*' -> units.*);
  lego_focal_verify confirms identical pass/flag state to pre-sweep
  (8 pre-existing structural flags, A/B-verified unchanged)
- tutorial/tools/test imports migrated (incl. binder test_units.py);
  book tests' legacy-symbol scanner treats a missing constants.py as
  'nothing defined'
- test_constants_allowlist.py rewritten as a deletion pin: the module
  (and any shim for it) must never return; core.units must keep the
  measurement surface (ureg, Q_, GB, BYTES_FP16, PRECISION_MAP, ...)
- test_mlsysim_registry_parity.py deleted: it compared registry values
  against legacy constants 'before deletion' — that migration is
  complete (registry gate list updated)
- Docs prose (DATA_MODEL, architecture, contributing) states the
  deletion instead of describing a retired shim

749 passed; binder registry gate green; star import intact.
2026-06-06 11:34:47 -04:00
Vijay Janapa Reddi
bb92b09bcc Extend Python formatter to executable LEGO cells and reformat corpus
The book-format-python hook's fence regex matched display blocks
(```python, ```{.python}) but skipped executable ```{python} cells,
so hand-aligned assignment columns accumulated unchecked in LEGO code
(931 aligned lines across 22 files).

Add a second formatting profile for executable cells:
- Black at 150 chars (keeps one-line fmt_* exports; the display-block
  70-char profile would explode them into multiline calls)
- --skip-string-normalization (preserves the corpus quote-style mix)
- #| option lines shielded with a sentinel (Black rewrites '#|' to
  '# |', which breaks Quarto cell options)
- no comment wrapping (LEGO box-drawing headers must not rewrap)
- blank-line runs collapsed to one inside cells, keeping cells compact
  and making output a fixed point for book-format-blanks, whose fence
  toggle can desync on commented-out partial code blocks

Apply the one-time mechanical reformat across both volumes. Black
verifies AST equivalence, so all cells are semantically unchanged;
binder math/code checks and the LEGO test suites pass.
2026-06-06 11:23:25 -04:00
Vijay Janapa Reddi
9a949752d9 Close chapter plot figures after rendering 2026-06-06 10:30:02 -04:00
Vijay Janapa Reddi
4c71d82867 Enforce footnote list placement and normalize emphasis 2026-06-06 08:50:19 -04:00
Vijay Janapa Reddi
7116e61f63 Merge section-flow pass into dev
# Conflicts:
#	book/cli/commands/validate.py
#	book/quarto/contents/vol2/distributed_training/distributed_training.qmd
#	book/quarto/contents/vol2/network_fabrics/network_fabrics.qmd
2026-06-05 18:16:52 -04:00
Vijay Janapa Reddi
245426f104 Align cross-reference casing after colons 2026-06-05 16:03:20 -04:00
Vijay Janapa Reddi
f5b34b32ab Align cross-ref colon casing with MIT Press
A plain-prose colon introduces a single clause, which MIT Press lowercases
(Chicago 17th 6.61 + 8.180), so the cross-ref prefix is mid-sentence: @sec-.
A colon after a bold run-in label (**Setup**:) opens a sentence and keeps the
capital. Previously every colon forced a capital, matching the engineering-
textbook habit the copyedit rejected.

- check refs --scope xref-case: split the colon branch (bold-label lead-in =
  sentence start; plain-prose colon = mid-sentence)
- lowercase the 7 prose-colon cross-refs the corrected check now flags
2026-06-04 22:06:51 -04:00
Vijay Janapa Reddi
b78fc60e33 Check H2 landing prose 2026-06-04 20:30:45 -04:00