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.
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.
- fmt_int: nonzero values that round to 0 now raise (the allow_zero
removal left fmt_int as a silent-zero path: fmt_int(0.4) rendered
'0'); rounding switched from banker's to half-away-from-zero so
adjacent halves agree (2.5 -> 3, was 2)
- Auto-scale counts promote at the rounding boundary:
fmt_params(999_999_999) -> '1B' (was '1000.0M'),
fmt_params(999_999_999_999) -> '1T' (was '1000B'); top scale falls
back to commas ('2,000T')
- fmt_unit now routes through the shared _UNIT_LABEL_NORMALIZATION
table (its divergent local map missed EFLOPs/KFLOPs rates and bare
work units), so fmt_val/fmt_unit table columns always match fmt_qty
prose suffixes. Visible alignment effects: 'Gbps' -> 'Gb/s',
'B' -> 'bytes' in a handful of table cells (now consistent with
adjacent fmt_qty prose)
- fmt_pp(-1) -> '-1 percentage point' (singular checked on magnitude)
- fmt_usd(-500) -> '-$500' (sign before currency glyph; approx and
scale/per variants handled)
20 new boundary tests; fmt suite 175 passed, full suite 751 passed.
fmt_pp previously only emitted plural "N percentage points", which blocked
migrating the ~17 corpus sites that legitimately use the singular noun or the
hyphenated attributive adjective ("a 5 percentage-point gap").
Now:
- noun form agrees with the rendered number ("1 percentage point" vs
"0.9 percentage points"); exact 1 renders singular.
- attributive=True yields the hyphenated compound-adjective form
"N percentage-point" (style='prose' only; rejected for symbol).
Adds 6 tests covering singular/plural agreement, fractional plural, attributive
hyphenation, and the symbol+attributive rejection. All 67 fmt tests pass.
Add allow_negative= to fmt_percent (widens the domain to [-max_ratio, max_ratio]
when a percentage is a SIGNED rate of change — ROI, cost delta — rather than a
bounded proportion). Default still refuses negatives, keeping the common case
strict. Adjudicate the 5 queued sites, all byte-identical to HEAD:
data_selection ROI cluster (-81.8% / -9.1% / +81.8% / +809.1%): store rois as
ratios (drop the *100 that only fed suffix='%') and format all four
consistently via fmt_percent(..., allow_negative=True, max_ratio=9).
ml_systems battery budget (320%): fmt_percent(..., max_ratio=4).
model_serving cost increase (300%): fmt_percent(..., max_ratio=4).
The percent value-kind is now 100% migrated corpus-wide. gitignore the
transient adjudication-queue artifact.
Typed/guarded range formatter owning the en-dash so authors never type a
hyphen between two values. MIT Press style: en-dash (U+2013), endpoints
written in full (1992-1993, never 1992-93). kind='number'|'usd', optional
unit appended once. Guards: finite endpoints + hi>=lo (inverted range is a
bug). Exported from mlsysim; 8 unit tests. Unblocks the MarkdownStr->typed
range migration (WS3).
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.
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.