Skip to content

PROD: lp612 v9.3 — the phone-first page (520x2000). DO NOT MERGE without the operator's go - #792

Draft
hyasin270 wants to merge 3 commits into
mainfrom
oak1616-phone-page-to-main
Draft

PROD: lp612 v9.3 — the phone-first page (520x2000). DO NOT MERGE without the operator's go#792
hyasin270 wants to merge 3 commits into
mainfrom
oak1616-phone-page-to-main

Conversation

@hyasin270

Copy link
Copy Markdown
Contributor

DRAFT — DO NOT MERGE. Prepared for the operator's decision in the morning. bd-oak77.16, lane prod_golive_2026-09-06/15_phone_page/.

Three commits, cherry-picked from develop (where they are merged and live on staging, verified by the running process) onto current main.


What it is

An A4 page opened in WhatsApp is fit to a ~390 CSS-px screen, so every size on it is multiplied by 390/794 = 0.4912 before a teacher reads it. 07_font took the type as far as A4 will carry it and measured where that lands: 67% of the critical print size for fluent reading. Closing it with type alone needs ×1.75 — a 36-page lesson. The other term in the arithmetic is the page.

520 × 2000, with the type untouched.

Measured on the file a teacher actually receives

Pulled back out of R2 after a real staging job — lp612/v9.3/en/grade_9_chemistry.c02.p020-023.pdf, page box 390 × 1500 pt = 520 × 2000 CSS px:

x-height on the phone arcmin @ 40 cm % of the 12-arcmin floor
the v9.1 PDF it was re-rendered from 0.920 mm 7.91 66%
the v9.3 PDF that replaced it 1.431 mm 12.30 102%

Urdu is judged on whether the nuqta survive the downscale: marks landing on 1–2 device pixels fall 29% → 9% on a native-Urdu lesson.

It costs no paper — it saves a quarter of it

Replayed over all 116 lessons production has delivered, origin/main against this branch:

pages median over cap documents with any defect NEW defects
origin/main (today) 1577 14 72 / 116 75
this branch 1130 (−28%) 10 1 / 116 5 0

All five remaining already fail on origin/main today. Total scrolling roughly doubles (8.5 → 16 phone screens); that is what 1.5× type in the hand means, and no page size avoids it.

The thing that would have broken production, found while preparing this PR

main's lint_lp.js imports FULL_COL from the template while still hardcoding minPx: 13.5. Under v9.3 that import silently becomes 455, and a 455px box judged against an A4 floor is — measured with the lint gate's exact check over the same 116 lessons:

floor column blocking FIGURE failures documents
today on prod 13.5 729 8 8 / 116
v9.3 with lint unfixed 13.5 455 159 101 / 116
v9.3, floor scaled by the PAGE 8.84 455 26 25 / 116
v9.3 as shipped, scaled by the COLUMN 8.43 455 8 8 / 116

FIGURE is not on ADVISORY_CODES — every one is a revision round the ladder spends and a lesson it can lose. 8.43 reproduces today's acceptance set exactly, the same eight documents. Commits 2 and 3 are that fix and the parity suite that now pins the invariant instead of A4's value for it.

The caps do not move

Not needed: over_cap falls 72 → 1. PAGE COUNT is a soft flag either way (lp612-render-policy: overCap, never blocking) and costs at most one revision round (PAGE_COUNT_ROUND_BUDGET = 1), so this can only reduce those rounds.

Design regression sweep — read as images, both languages

Every diagram type (29, incl. 11 with no real example in the corpus) and every block type rendered at 390px in English and Urdu and read. Four defects found by looking, not by grepping — the footer wrapping 74px → 188px on every page, and .hero / .p2head / .nxt / .se laying two columns at a 478px measure — all fixed. Collapsing them saves ~30 pages.

Gates

  • 00_vehicle/extract/bootproof.js in a fresh npm ci: 27/27 loaded, 0 failed
  • delta gate vs a fresh origin/main worktree: failing set IDENTICAL (2 suites / 7 tests, both pre-existing), +17 passing
  • tests/lp612/phone-page.test.js RED 11/13 → GREEN 17/17
  • staging: all three services SUCCESS on 6d946ec3, LP_612_TEMPLATE_VERSION=v9.3, two real jobs through the deployed worker — EN 16→11 pages and UR 18→11 pages, model_used: reused:v9.1, rounds_used: 0, ~5 s, and 0 LLM events on either correlationId in Axiom against a live control of 16 in the same window

The prod change, in order

  1. merge this PR (code)
  2. then LP_612_TEMPLATE_VERSION=v9.3 on bot, sqs-worker, sqs-worker-video

LP_612_TEMPLATE_FALLBACK stays unset. Rollback is LP_612_TEMPLATE_VERSION=v9.2 — one variable, no deploy, and the v9.2 renders are still in the cache.

Known, pre-existing, and unchanged by this PR: 2 of the 116 cached lessons carry a stored Urdu overlay on a machine field that today's validator refuses, so they fail to re-render. Reproduced identically targeting v9.2, so it is a property of those stored documents, not of the page. LP_612_TEMPLATE_FALLBACK= (empty) turns reuse off entirely if that matters more than the spend.

Refs: bd-oak77.16

Haroon Yasin and others added 3 commits September 8, 2026 01:09
…he reading floor

07_font took the body as far as A4 will carry it and measured, honestly, where that lands.
An A4 page box opened in WhatsApp is fit to a ~390 CSS-px screen, so every size on it is
multiplied by 390/794 = 0.4912 before a teacher reads it, and the 21px body arrives at
0.930 mm of x-height — 7.99 arcmin at 40 cm, 67% of the critical print size for fluent
reading. Closing that by type alone needs x1.75, which costs 2,261 pages over the corpus:
a 36-page lesson. The other term in the arithmetic is the PAGE, and this is that change.

    apparent x-height (mm) = font_px x 0.5411 x (390 / PAGE.w) x 0.16667

520 x 2000, with the type untouched. MEASURED on a real production lesson re-rendered from
its stored document: 0.920 mm -> 1.431 mm, 7.91 -> 12.30 arcmin at 40 cm. 102% of the floor.
Urdu is judged on whether the nuqta survive the downscale rather than on an ink band: marks
landing on one or two device pixels fall from 29% to 9%.

WHY 2000 TALL. Page count is set by page AREA, so a narrow page keeping A4's proportions is
just A4 with 31.5px type. Height buys the area back. Measured over the 62-document corpus AND
all 116 lessons production has delivered, this page costs FEWER pages than today:
1,577 -> 1,131 on production traffic, median 14 -> 10. Total scrolling roughly doubles and no
page size avoids that — it is what 1.5x type in the hand means.

WHAT A NARROW MEASURE BREAKS, and what was done about it. Found by rendering every diagram
type and every block type at 390px in both languages and READING it, not by grepping:

  * the footer was a two-column row built for a 752px measure. At 478px it wrapped to four
    lines and went 74px -> 188px ON EVERY PAGE, which is what pushed 29 of 62 documents into
    OVERFLOW with overflowingSections EMPTY — the strip that prints "page 6 of 14" over the
    line, past bd-c3le6's 12px absorber. Stacked, it measures 74px again.
  * .grid2 / .grid3 / .split / .secrow / .hero / .p2head / .nxt / .se all laid two or three
    equal columns. A .grid3 cell at this measure is 154px; .hero's meta column shrank to
    ~110px and stole the width from the title — the same pathology its own comment records at
    794px, one page size down. All collapse to one column, which SAVES 30 pages rather than
    costing them.
  * the diagram label floor MUST scale with the page: held at 13.5 it produced 154 FIGURE TOO
    SMALL defects across 99 of the 116 real lessons. Scaled, 5 — against the A4 baseline's 4.
    A diagram label therefore arrives at exactly the size it does today; raising it is
    bd-oak77.15's and needs simpler diagrams, not a bigger floor (the sweep is in DESIGN.md).

THE CAPS DO NOT MOVE, and did not need to. At this geometry the worst of the 62 documents is
EN 6/6 against 7/6; on the 116 production lessons over_cap falls from 72 to 1. PAGE COUNT is
a soft flag either way (lp612-render-policy: overCap, never blocking) and costs at most one
revision round (PAGE_COUNT_ROUND_BUDGET = 1), so this change can only reduce those rounds.

ZERO NEW FAILURES, diffed document by document on both corpora: 62-doc 4 problem documents
-> 0; production 75 -> 8, and every one of the 8 already fails on today's format.

The page is ONE frozen object with a named format, so a printable A4 variant is a parameter
rather than a rewrite (priced in DESIGN.md section 7). Template version v9.2 -> v9.3, lineage
['v9.3','v9.2','v9.1'] — the schema is untouched, so every cached lesson RE-RENDERS from its
stored lp.json for zero model spend. Rollback is LP_612_TEMPLATE_VERSION=v9.2, no deploy.

Measurement, both corpora, the printing trade-off and the recommendation:
prod_golive_2026-09-06/15_phone_page/DESIGN.md

Refs: bd-oak77.16

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… instead of a literal

Preparing the cherry-pick onto `main` surfaced a coupling `develop` does not have, and it would
have broken production. `main`'s `lint_lp.js` already imports `FULL_COL` from the template
(bd-oak77.14, "one definition, imported") while still hardcoding `minPx: 13.5`. Under v9.3 that
import silently becomes 455, and a 455px drawing box judged against a 13.5px floor is, measured
over the 116 lessons production has actually delivered:

    159 BLOCKING `FIGURE` failures across 101 of 116 documents

`FIGURE` is not on `ADVISORY_CODES`, so each one is a revision round the authoring ladder spends
and a lesson it can lose. Importing half a pair of coupled constants is strictly worse than
importing neither. Both are imported now.

AND THE FLOOR ITSELF WAS SCALED BY THE WRONG THING. `pageScaled` uses PAGE.w/PAGE_A4.w = 0.6549,
but a figure's labels scale with ITS COLUMN, and `padX` and `FIG_CHROME` are absolute pixels that
did not shrink with the page — so FULL_COL/FULL_COL_A4 is 0.6242, not 0.6549. Measured, on the
same 116 lessons, with the lint gate's exact check:

    floor 13.5 in a 455px column (unfixed)        159 failures across 101 documents
    floor  8.84 (scaled by the PAGE)               26 failures across  25 documents
    floor  8.43 (scaled by the COLUMN) — SHIPPED    8 failures across   8 documents
    TODAY on prod (13.5 in a 729px column)          8 failures across   8 documents

8.43 reproduces today's acceptance set exactly — the same eight documents — so no lesson that
authors today can fail to author because of this change. The renderer agrees: FIGURE defects over
the production corpus go 4 -> 2, and problem documents 75 -> 5 with zero new ones.

WHAT IT COSTS, SAID PLAINLY rather than left implied: a diagram's smallest label arrives on the
phone about 5% smaller than today (6.32 phone px against 6.63). That is the price of keeping the
21px gutters, which this lane deliberately did not narrow, and it is 5% off a mark already at 43%
of the reading floor. ACCEPTANCE-neutrality is what protects a teacher's lesson; the 5% is
bd-oak77.15's to win back, and it needs simpler diagrams rather than a bigger floor.

Evidence: 15_phone_page/scripts/lint_floor_probe.js + tests/LINT_FLOOR.txt
Refs: bd-oak77.16

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…value for it

`expect(T.FULL_COL).toBe(729)` pinned the number rather than the derivation, so it failed for the
one reason this suite exists to allow: the column moving in ONE place and every gate following it.
It now asserts FULL_COL === PAGE.w - 2*padX - FIG_CHROME, keeps 729 as FULL_COL_A4, and covers the
half bd-oak77.16 found missing — that lint imports the FLOOR as well as the column, and that the
floor is scaled by FULL_COL rather than by the page width.

This file exists only on `main` (it never reached develop), so the fix rides the cherry-pick.

Refs: bd-oak77.16

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@hyasin270
hyasin270 force-pushed the oak1616-phone-page-to-main branch from c9b58f2 to 5e2c93f Compare September 7, 2026 20:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant