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.
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.
Expand lego-prose-units for FLOP/byte and carbon-intensity glyphs, add regression tests and an explicit audit report, and strip redundant g/kWh after fmt_carbon_intensity refs in sustainable_ai.
flop (and the OPS/TOPS integer-op family, which shares compute-rate
fields with TFLOP/s) now lives on a dedicated [flop] base dimension
instead of being a dimensionless count alias. Compute throughput can
no longer silently add to or convert into memory bandwidth — the
category error pint previously accepted ('989 TFLOP/s + 3.35 TB/s')
now raises DimensionalityError at the expression. Bytes, counts,
params, and dollars stay dimensionless so params x bytes/param and
similar compositions are unchanged; arithmetic intensity carries
[flop] and divides cleanly; MFU reduces to a dimensionless fraction.
- Seven schema validators updated to the honest families (peak_flops,
precision_flops, inference_flops, total_ops, training_ops,
compute_threshold -> flop-rate/flop; arithmetic_intensity ->
flop/byte)
- tech/op.yaml normalized: per-op energies were inconsistently 'pJ',
'pJ/flop', and 'pJ/count' (identical under the old aliasing, three
different dimensions now); all are pJ/flop, so N flop x pJ/flop
composes to energy directly; Op.energy validator matches
- book/tests/test_units.py: 6PD training ops now via the canonical
calc_transformer_training_flops (a bare params x tokens product is a
count, not work); INT8 energy read in pJ/flop
Verification: 749 mlsysim tests + 20 book unit tests pass; whole-book
lego_focal_verify identical to baseline (zero cell fallout — the May
unit-hardening had already put cells on .to(unit).magnitude
discipline); registry gate green; examples + paper anchors pass.
Five references outside the gate scopes: the two runnable examples,
the paper's anchor validator, book/tests/test_registry.py, and a
LEGO_CELLS.md prose mention. All verified executable post-migration
(examples 03/04 run; validate_anchors: all 7 anchors match).
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.
- math.qmd: three GitHub links had a tripled mlsysim/ path segment
- models-and-solvers.qmd: DSE link pointed at deleted core/dse.py
(now engine/dse.py)
- data_engineering/benchmarking LEGO headers still cited retired
core.constants names (NETWORK_100G_BW, GPT3_TRAINING_TOKENS,
GPT3_TRAINING_ENERGY_MWH); comments now name the actual registry
sources the cells read
- book/tests/test_units.py: fmt_unit FLOP-count expectation updated to
the shared-label singular form ('GFLOP'), matching the fmt dedup
Extend audit_prose_semantics.py with checks that need the substituted value:
- mult_direction: a sub-unit multiple asserted to go UP ("0.5x faster",
"0.3 times larger") is self-contradictory.
- currency_as_percent: a "$N percent" value-kind mismatch.
Add book/tests/test_audit_prose_semantics.py (7 cases) pinning every pattern to
fire on known-bad rendered prose and stay quiet on legitimate sentences
(including display-math lines that carry an inline ref). Corpus clean.
Make fmt_prose_contract key its formatter map by QUALIFIED name (Class.attr)
with an ambiguity-safe lookup, fixing two usd_dup false positives where two
classes export the same bare attr with different formatters (one fmt no-$, one
fmt_usd with-$) — a qualified prose ref must use its own class's glyph rule.
With the checker now trustworthy, it caught a genuine pre-existing bug in
robust_ai: acc_drop (76-50 = 26 percentage POINTS) was formatted as a percent
("26 percent") while the prose appends "percentage points" -> "26 percent
percentage points". Fixed to a bare number (prose supplies the unit), matching
the sibling RobustnessTaxRecap.acc_drop_str. Corpus contract now fully clean.
fmt(x / MILLION, suffix='M') -> fmt_count(x, scale='M', precision=...): strip
the division and declare the scale once (fmt_count divides by the same factor
and guards counts >= 0). Only the clean case migrates — the divisor magnitude
must match the glyph, so output is unchanged; 41 sites across 10 chapters pass
the byte-identical gate.
Generalize run_percent_lane's gate into a reusable lane_process(scan_fn,
fn_name, dup_codes) + _ensure_import(fn_name); run_scale_lane reuses it. The
pre-scaled / lowercase-'k' / spaced-glyph / fmt_int sites are queued for a
source-level decision (keep the raw count) rather than re-multiplied.