Skip to content

fix(oxbridge): install Chromium system libs on Railway + wait for images in PDF render - #2

Merged
mashhoodr merged 1 commit into
mainfrom
bd-2024-65449
Jul 16, 2026
Merged

fix(oxbridge): install Chromium system libs on Railway + wait for images in PDF render#2
mashhoodr merged 1 commit into
mainfrom
bd-2024-65449

Conversation

@mashhoodr

Copy link
Copy Markdown
Contributor

Summary

Oxbridge lesson-plan PDFs have been silently failing on the NIETE deployment for 48+ hours — teachers get text-only fallbacks with the <img> tags stripped.

Two root causes, both fixed here:

  1. Chromium system libs missing on Railway — Playwright's bundled Chromium loads libglib-2.0.so.0 / libnss3 / etc. at runtime. Neither railpack.json nor nixpacks.toml declared them, so chromium.launch() exited 127 on every call. This adds railpack.json with the full apt-package list Playwright's Chromium needs (mirroring the pattern our sibling PK bot uses successfully), plus the same list in nixpacks.toml as a fallback.

  2. waitUntil: 'domcontentloaded' returns before remote <img> src fetches settle — page.pdf() would then snapshot the DOM with unloaded image nodes. Switches to 'networkidle' so S3-hosted lesson-plan diagrams actually render into the PDF.

Also promotes the swallowed catch in deliverOxbridgeLp from info-level to level='error' so the next silent failure pages Axiom instead of hiding in noise.

Test plan

  • Added regression test asserting waitUntil: 'networkidle' in the html-to-pdf suite (fails before Fix 2, passes after)
  • Added new oxbridge-lp-error-level.test.js asserting the swallowed catch emits at level='error' (fails before Fix 3, passes after)
  • Full test suite: no new failures vs. baseline main (12 failing suites pre-existed; my 2 new suites both pass)
  • node --check on both modified bot files
  • Local require('./bot/shared/utils/html-to-pdf.js') loads clean
  • Post-deploy: verify PDF render succeeds on NIETE Railway with a real Grade 7 Oxbridge request; grep Axiom for absence of "PDF render/send failed" and presence of "PDF generated successfully" with a size that indicates image bytes are embedded

…ges in PDF render

Playwright was silently failing every PDF render because glib was missing
on the container. Text-only fallback stripped <img> tags, so teachers saw
lesson-plan text with no diagrams. This change:

  1. Adds railpack.json declaring the Chromium runtime apt packages
     (libglib2.0-0, libnss3, libgbm1, ...) so chromium.launch() no longer
     exits 127 with "error while loading shared libraries". Also mirrors
     the same list into nixpacks.toml as a fallback.

  2. Switches htmlToPdf's page.setContent from waitUntil='domcontentloaded'
     to 'networkidle' so remote <img> src fetches (e.g. S3-hosted lesson-plan
     diagrams) resolve before the PDF snapshot. domcontentloaded returned
     while images were still in flight, so page.pdf() captured unloaded
     <img> nodes.

  3. Promotes the swallowed catch in deliverOxbridgeLp from info-level to
     level='error' so the next failure pages Axiom instead of hiding in
     the noise floor.

Adds regression tests: the html-to-pdf suite asserts waitUntil='networkidle',
and a new oxbridge-lp-error-level test asserts the render/send catch logs at
error level.
@mashhoodr
mashhoodr merged commit 3b3c0e8 into main Jul 16, 2026
1 check passed
hyasin270 pushed a commit that referenced this pull request Sep 7, 2026
…ight

Operator, 2026-09-07: "the reminders that teachers get that no one has attempted
their quiz are annoying. Perhaps once after six hours is ok, but are we doing
more than that?"

Measured on production first. The nudge was ALREADY once per quiz — 118 events
across 118 distinct quizzes, no duplicates. Three things were wrong anyway:

1. SIX HOURS, NOT THREE. NUDGE_AFTER_MS was 3h, which caught classes that simply
   had not got home yet.

2. QUIET HOURS, DEFERRED NOT DROPPED. The class report already pushes anything
   landing between 22:00 and 07:00 PKT to the morning; the nudge pushed nothing.
   Today's nudges by PKT hour ran 12:5 13:4 14:24 15:25 16:22 17:7 18:7 19:10
   20:3 21:10 — ten teachers were told at 9pm or later that nobody had opened
   their quiz. Anything due 21:00-07:00 PKT is now held to 07:00 and still sent;
   the worker's existing re-queue loop waits it out.

3. ONE PER TEACHER PER DAY, NAMING THE QUIET LESSONS TOGETHER. It was once per
   QUIZ: 117 nudges reached 109 teachers, six got two and one got three, because
   teachers record up to four lessons a day. What that feels like is nagging,
   not a reminder about quiz #2. Now the first nudge of the day gathers the
   teacher's other quiet lessons, names them in ONE message, and stamps every
   one of them so none can nudge on its own later.

New catalog string tqNudgeMany (en + ur) via resolveUx — no inline map, no
ternary, no English floor.

Red-first: tests/quiz/transcript-quiz-nudge-cadence.test.js, 12 cases, 10 of
them failing before the change. Suites: root tests/quiz 1,975 pass (1 known
pre-existing failure, flushShelf > deletes the shelf key, unrelated).

Closes: bd-mg9c7.146

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit f6ea63f)
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