13 Commits
Author SHA1 Message Date
Vijay Janapa Reddi e7fea49e8a Migrate word-form time suffixes 2026-05-31 11:50:21 -04:00
Vijay Janapa Reddi c33f10c4b8 Migrate service rate suffixes 2026-05-31 11:19:08 -04:00
Vijay Janapa Reddi e270c36044 Migrate clean quantity-backed unit suffixes 2026-05-31 11:14:50 -04:00
Vijay Janapa Reddi ab3ae0086b Complete time unit suffix migration 2026-05-31 11:10:42 -04:00
Vijay Janapa Reddi ab1fffca1f Resolve scale count spacing with fmt_count 2026-05-31 07:29:10 -04:00
Vijay Janapa Reddi b216587485 Add byte-identical unit fmt lane 2026-05-31 07:04:50 -04:00
Vijay Janapa Reddi 203851e5f8 fmt(WS1): scale division -> fmt_count across 10 chapters (byte-identical)
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.
2026-05-30 21:48:33 -04:00
Vijay Janapa Reddi ddbb6c2a6f fmt(WS1): migrate fmt_int percents (17 chapters) — percent now 100% done
fmt_int(x, suffix='%'|' percent') -> fmt_percent(round(x)/100, precision=0,
commas=True, style=...): rounding first reproduces the integer percent
byte-for-byte (round(x)/100*100 == round(x)), so these flow through the same
byte-identical gate as the fmt('%') lane. 64 fmt_int sites across 17 chapters.

Adjudicate the final straggler (model_serving p_post_str, prefix='~'): relocate
the "~" approximation marker into the table prose and migrate the formatter to
match its sibling cluster — composite "~1%" verified byte-identical to HEAD.

scan_percent now reports 0 auto-rewritable and 0 queued: the percent value-kind
is fully migrated corpus-wide.
2026-05-30 21:44:10 -04:00
Vijay Janapa Reddi 9400222ef5 fmt(WS1): fix silent-drop of multiline percent calls; migrate the 3 stragglers
scan_percent emitted edits for multiline fmt(...) calls that the single-line
applier could never splice, so they were silently left as fmt(suffix=' percent')
while their cell-mates migrated. Now multiline calls are routed to the queue
(consistent with the multiplier lane) + a regression test. Hand-migrate the 3
multiline sites in appendix_assumptions (overhead_total x2, overhead_useful):
strip the *100, fmt_percent(..., style='prose'). Verified byte-identical to HEAD
(0/275 value diffs, 0 prose diffs).
2026-05-30 21:40:15 -04:00
Vijay Janapa Reddi b28a666c79 fmt(WS1): percent -> guarded fmt_percent across 37 chapters (byte-identical)
Move fmt(x, suffix='%'|' percent') into the typed fmt_percent formatter via a
strict byte-identical gate (run_percent_lane.py): every exported _str AND every
visible-prose preview must match before/after, else the file is reverted
untouched. ~520 sites now flow through fmt_percent's max_ratio guard with zero
change to rendered output — the "10,000%" class of bug can no longer render.

The rewriter is value-honest: fmt(ratio*100, '%') -> fmt_percent(ratio) (drops
the redundant *100), standalone fmt(foo_pct, '%') -> fmt_percent(foo_pct/100).

5 chapters intentionally NOT migrated (gate reverted, surfaced for adjudication):
  - data_selection / ml_systems / model_serving: values are -81.8% / 320% / 300%
    — the guard correctly refused; these need max_ratio= or reclassification.
  - responsible_engr / appendix_inference: need fmt_percent added to imports.
2026-05-30 21:27:38 -04:00
Vijay Janapa Reddi f20b5ac888 fmt(assess): class-qualify multiplier vars (fix cross-class name collision)
Two cells can export the same bare attr (e.g. ratio_str) where only one is
auto-rewritten and the other (fmt_int) is queued. The bare-name prose patch
wrongly appended $\times$ to the non-rewritten one (60×->60××). Track
mult_vars as Class.attr and match prose refs on the full qualified name
(bare only for module-level exports). Regression test reproduces the
data_engineering case.
2026-05-30 21:08:15 -04:00
Vijay Janapa Reddi c29006f499 fmt(assess): harden multiplier codemod (commas default, exact-glyph only)
Gate feedback from the corpus run:
- inject commas=True when the original fmt() omits it (fmt defaults True,
  fmt_multiple defaults False) so grouping like '5,000×' is preserved;
- restrict the auto lane to the EXACT '×' glyph; route literal 'x'/'X' and
  space-padded ' ×' suffixes to a 'multiplier-variant' queue (ambiguous:
  'x' may be a variable/axis, spacing differs);
- decline any call carrying prefix= (fmt_multiple has none).
4 new regression tests (13 total).
2026-05-30 21:03:27 -04:00
Vijay Janapa Reddi fa8316c86a fmt(assess): paired multiplier codemod + adjudication queue
codemod_fmt.py with two strictly separated lanes:
- PROVABLE (auto): fmt(...,suffix='×') -> fmt_multiple(...) in the cell +
  $\times$ after each prose ref. fmt and fmt_multiple share the precision
  guard, so the rendered magnitude is byte-identical; only the glyph moves
  (Regime 2). Prose patch is position-based so repeated refs on one line
  (tables, multi-factor sentences) each get exactly one glyph.
- QUEUE (never auto-touched): suffix='%' (fmt_percent needs a 0-1 ratio,
  source scale unknowable), K/M/B scale, multi-line, and fmt_int multipliers
  (fmt_int rounds; fmt_multiple guards against it) -> JSON queue with the
  decision each needs.

Default dry-run; --write applies. Proven end-to-end on training.qmd: 21 cell
+ 26 prose edits, values change (× dropped) but visible prose IDENTICAL via
assess_equiv, prose-contract clean, 61 ambiguous sites queued. 9 unit tests.
2026-05-30 20:46:49 -04:00