Aelira Core v0.10.0: a second reading for every printed equation
Aelira Core v0.10.0 reads every printed equation twice, blind, and fixes a review gap we found hours after publishing v0.9.13. It also explains why the release took five days.
We published Aelira Core v0.9.13 on 20 October. Less than three hours later, we opened two issues against our own code for reading printed equations. Its check could accept a reading with one wrong symbol, and the alt text it produced could reach a remediated PDF without the human review meant to hold it. Four hours after publication the release notes carried a warning, and we held the announcement until the fix was ready. v0.10.0 is that fix, plus what we found while making it. This post covers both releases.
What was wrong with printed equations
When an equation in a PDF exists only as an image, Aelira asks a vision model to read it as LaTeX. Until v0.10.0 that reading had one check: render it and compare the render with the original. If they looked close enough, the reading counted as verified.
Looking close is not the same as being the same. Drawn out, x cubed plus 3x minus 7 looks almost exactly like x squared plus 3x minus 7. In an internal benchmark of 100 readings that each had one wrong symbol, the check accepted 25 on v0.9.12, and that code was unchanged in v0.9.13. Our v0.9.6 and v0.9.7 notes had called these equations "round-trip verified". That was only true for handwritten equations, and both notes now carry dated corrections.
Who was actually exposed
We then traced every release from v0.9.6 to v0.9.13 to see which real jobs could put that alt text in front of a user. The answer was narrower than our warning, and not the one it named.
Printed equations never produced a downloadable file in any shipped job type. A separate bug made those jobs fail before the file was saved: the record of each fix had to name the AI model, and our learning-platform connections never supplied one. The exposure was handwritten equations, in Canvas, Blackboard or Brightspace jobs with AI image descriptions on. In v0.9.12 and v0.9.13, a verified handwritten equation could drop off the review list while its alt text stayed in the PDF. v0.9.7 to v0.9.9 kept those equations waiting for human review. Code reading could not settle v0.9.10 and v0.9.11, so treat them as affected. The v0.9.13 release notes now carry a dated correction.
If that describes your use, compare the alt text of each handwritten equation in those PDFs with the original before relying on it.
Equation recognition that never ran
The tracing turned up a larger problem. Since v0.9.7, equation recognition has not run at all for local uploads or Google and Microsoft files. Those jobs use the workspace's own AI provider, and the equation reader only accepted a connection labelled for image descriptions, a label the workspace connection never carried. When a PDF held an equation image, those jobs also dropped image descriptions for the whole file. Every other image went to manual review with a message saying no AI provider was available, although one was configured.
v0.10.0 gives those jobs a narrowly scoped, description-only view of the workspace's provider. Equation recognition now runs for self-hosted uploads, other images keep their descriptions, and every reason an equation stays manual has an accurate explanation (#732).
What v0.10.0 changes
A blind second reading. After the visual check passes, a second reader transcribes the same image in a separate call with its own fixed prompt. It never sees the first reading: the code that calls it has no way to pass that reading along. Both readings are converted to a standard form of MathML and must match exactly. Otherwise the equation stays with a person. The blindness is the point: a reader shown the first answer tends to agree with it.
On a new test set of 52 multi-term equations, each read with one wrong symbol, the visual check alone accepted 20. With a correct second reading, the full check accepted none. CI records that figure on every run. The limit matters as much as the result. The readings come from separate calls, not necessarily separate models, so they can share a mistake. A person still approves every equation before it is downloaded or sent back to the learning platform.
Before merging, two rounds of internal audit tried to break these checks. They found real gaps, from maths inside dollar signs slipping past the description check to Australian prices like A$5 being wrongly refused. Each now has a test.
Alt text only where the words cannot mislead. Equation alt text is built from the LaTeX by substitution, which can give different equations the same words or drop a function name (\sin x = 0 read as "x = 0"). v0.10.0 writes it only for simple forms its rules can speak one way, and leaves the rest for review. The rules are conservative, but they are checks we keep testing, not a proof. Speech generated from the verified MathML is next (#698).
A review step that cannot be skipped. If equation content that needs review reaches the saved file without a verified fix behind it, the job stops and sets the file aside. A separate publishing check also refused every remediated file containing an equation, because remediated files never carry the PDF/UA identifier it checked. It now blocks only failures that remediation introduces (#697).
Descriptions in words, and readings models actually produce. Image descriptions written in raw LaTeX are refused rather than read aloud as backslashes and braces (#710). Model answers that write LaTeX with single backslashes, which JSON rejects or turns into control characters, are now repaired. Before, almost no printed equation got through recognition with our default local model (#705). Thank you to Vamsi-2581 for an independent fix (#712).
A more honest label. "Change applied · automated check passed" now reads "Change applied · finding no longer detected", with "human review required" where that applies. A rescan shows a finding is gone, not that the change is right.
Other fixes
- Transcripts no longer invent speakers from pauses and wording (#649).
- PowerPoint scans read alt text from the right element, so described pictures stop counting as missing, and file names or placeholders like "Picture 3" do count as missing (#713).
- Multi-line descriptions are folded, not discarded (#711).
- An undescribed image no longer withholds a whole untagged PDF (#714).
- Descriptions bind to the exact image they describe or are not written (#715).
- Equation canonicalisation, binomials and oversized equations (#690, #691, #692), and image build fixes (#700, #706).
Command line
While capturing a real sample for the CLI README, we found that the document scan commands printed File: Unknown and no score, counts or scan ID, because they read fields from the wrong level of the API response. A pass over the CLI fixed that and some related rough edges.
scan pdf,scan docx,scan xlsx,scan ppt,scan codeandscan latexnow print the file, score, counts and scan ID the API returns. Their CSV output has finding rows, andaelira exportwrites findings (#772, #762).scan webandscan watchwait for the scan to finish and report its real result, where before they printed the acknowledgement of a queued scan.scan web --batchtakes the URLs to scan,--depthsets how far links are followed, and the export date column is now labelleddate_utc(#775).- Console scores are labelled "Scanner score", since an automated score is not a conformance rating. Emoji are gone from terminal output, because screen readers read them aloud by name (#772).
aelira interactiveno longer clears the terminal, so screen reader users keep their scrollback. It prints the logo only on an interactive terminal, andNO_COLOR,TERM=dumb,CI,AELIRA_NO_BANNERor--no-bannerturn it off (#770).
Security, and why it took longer
We planned to follow v0.9.13 within days with the equation fix alone, and to move the open security work to a later release. Then the advisories kept arriving. Between 20 October, when v0.9.13 shipped, and 25 October, when v0.10.0 did, the GitHub advisory database published 33 advisories for components in our image. Alongside them came Chrome's 20 October security release and eight ImageMagick advisories that Debian has not fixed. Shipping on the original plan would have meant publishing a release we already knew was exposed, so we held it and did the security work first.
By publication date:
- 20 October.
certifi(critical), nine for Pillow (one critical), two forfollow-redirects, and Chrome's browser fixes. - 21 October. PDFium and pypdf.
- 22 October. Brotli (critical).
- 23 October. Node.js (six),
filelock(six),setuptools, and five in development-only CLI tooling. - The same week. Eight ImageMagick advisories with no Debian fix.
v0.10.0 fixes every one of these or shows why it does not apply to our image, with two exceptions described below: the PDFium advisory, which has no fixed release yet, and one ImageMagick slowdown, held to a 60-second limit until a rebuilt package ships.
What changed, by component:
- Image and PDF parsers. Pillow 13.0.0 fixes nine advisories, one critical: a heap overflow in JPEG decoding that images inside uploaded PDF, Word and PowerPoint files reach (#729). pypdf 6.21.2 fixes one that let image data claiming to be JPEG reach other image parsers, and adds limits on parsing work (#743). PyMuPDF 2.0 brings MuPDF 1.28.5 and its memory-safety fixes (#742).
- Trust stores.
certifi2026.10.19 removes a root whose intermediate CAs have compromised keys (GHSA-6q48-6c7w-9gw2, critical). It is gone from pip's copy, the system store and now Node's store too, and a build check enforces all three (#723, #726). - Media. The image no longer installs Debian's FFmpeg.
ffmpegandffprobenow come from our own FFmpeg 9.0.2 build, limited to local files, which removes about 110 packages and 22 advisories we had only been reasoning our way around (#748). - Browser. The scanner runs a hash-pinned Chrome for Testing 156.0.8078.47 on Node.js 24.22.1. Playwright's bundled Chromium predates the browser fixes published on 20 October (#745, #746).
- LaTeX conversion. We rebuilt Debian's libxml2, libX11 and libXrender with the upstream fixes for eleven more advisories, alongside the libxml2 fix v0.9.13 already carried. Each rebuild is hash-pinned, ships with a build receipt, and is checked in the final image. Our v0.9.12 notes said no distribution fix existed for the libxml2 ones; that was out of date, and the notes now carry a dated correction (#579, #605). ImageMagick, which LaTeX conversion uses for graphics, now refuses every format except the five it actually needs, and runs each tool with an empty home directory so a document cannot loosen that policy. Of eight newer ImageMagick advisories without a Debian fix, seven do not apply to our setup; the eighth is described below (#749). A ninth, published the day after this release, does not apply either: it is in the handling of bzip2-compressed files, which the converter refuses before ImageMagick runs. Its reasoning is in our list of reviewed advisories (#826).
- Brotli. Debian's fixed
libbrotli1(DSA-6582-1) closes CVE-2026-111497, a critical overflow in the Brotli decoder that libcurl, FreeType and libheif load. We had rebuilt Debian's package ourselves while waiting, and retired that rebuild once Debian's update arrived. The Pythonbrotlipackage is at 1.2.1, and the scanner's Node.js carries the same fix in its own copy (#774). - Smaller updates.
filelock4.2.4 (six advisories) andsetuptools84.2.1 (#787), and the dashboard'sfollow-redirects1.16.1 (#721). Two development-only updates in the CLI's tooling are not part of the published package (#793).
Some advisories remain open. Debian packages that are still waiting on a Debian fix stay on our published list of reviewed advisories, each with its reasoning and a review date. Three remaining items are ours to track. An ImageMagick slowdown (CVE-2026-106576) needs a rebuilt package; a crafted image can tie up a conversion until our 60-second limit stops it, and the rebuild is scheduled for a later release (#750). A MuPDF double free (CVE-2026-112036) is not fixed in MuPDF 1.28.5, the version PyMuPDF 2.0 bundles, and only affects PDFs whose signature fields carry /Lock dictionaries (#755). The PDFium inside pypdfium2, which OCR uses to render uploaded pages, predates a fix and no fixed release exists (#747).
One change carries a caveat. A high-severity zod advisory (GHSA-mrhx-c7xc-m3w5) has no fix for zod 3, so the scanner runtime now forces zod 4.6.7. Its browser-protocol library, chromium-bidi, was written for zod 3 and throws a TypeError, instead of a clean error, when it validates invalid input. Scans do not load that library, because Pa11y is pinned to the Chrome DevTools Protocol, and a build check enforces both. The clean fix is Pa11y 10, planned for a later release (#786). The disclosure has the details.
Our hosted service ran the affected Pillow and certifi versions. On 21 October we paused anonymous demo uploads for 42 minutes while we deployed those fixes. The rest of this release's security fixes reached the hosted service on 25 October (UTC), and its equation fixes on 26 October. If you run v0.9.13 or earlier, upgrade.
If you are upgrading from v0.9.12
You also get v0.9.13: generated captions delivered for review instead of discarded, unmeasured video kept "Unassessed", a patched libxml2 for LaTeX conversion, no text-only image descriptions in document remediation, and dashboard accessibility fixes. v0.9.13 adds database migrations, so back up and follow the upgrade procedure. v0.10.0 adds none.
This release is numbered 0.10.0 because it adds features and changes CLI output. Our 0.9.x releases did the same as patch bumps, which Semantic Versioning reserves for compatible fixes. From now on, minor releases carry features and breaking changes, and patch releases carry only fixes and security updates.
What operators need to do
- Upgrade the API, worker and dashboard together from the same release.
- Re-run remediation on documents with equations. Equation evidence from earlier versions now reads as invalid, and those files stay gated until regenerated.
- Local, Google and Microsoft jobs now send equation images to your workspace's configured provider, the same one that already receives images for descriptions. An explicit
generate_alt_text: falseis now honoured. - Speaker labels and PowerPoint results from earlier scans stay until the media or deck is rescanned.
- Each API and worker process can use up to about 90 MB more memory, because PyMuPDF 2.0 ships a layout model that loads on import.
- Scripts that read the CLI's output need checking.
scan web --format jsonnow returns the finished scan detail instead of the queued acknowledgement, console wording changed,scan web --batchnow takes the URLs to scan, and the export date column isdate_utc. - Media files whose MOV or Matroska headers are zlib-compressed, a rare legacy format, no longer decode with the new FFmpeg build.
An automated score describes the checks we implemented. It does not establish accessibility conformance, and a remediated document still needs review before publication.
The whole self-hosted product remains free and open source. The repository now has a supporters list for people who sponsor the project, and listing is opt-in. Sponsorship buys no roadmap control or support guarantee (#765). Download Aelira Core v0.10.0 and read the release notes.

RD (Reg) Crampton
•Founder & CEOFounder, CEO & lead developer of Aelira. Building beta tools to help faculty and accessibility teams check materials and evaluate suggested fixes, with human review required.
Related Articles
Aelira Core v0.9.12: publishing the security record with the release
Aelira Core v0.9.12 fixes a LaTeX file-access vulnerability, publishes three security advisories, discloses every unfixed image advisory and adds reviewed PDF working files.
I applied for GitHub's security fund. Then CodeQL found 42 alerts.
We applied for GitHub's security fund, then CodeQL raised 42 alerts. Here's what we changed, deployed and still need to review.
Aelira Core v0.9.6: accessibility remediation that knows when to stop
Aelira Core v0.9.6 adds equation and table remediation, durable document queues, safer Canvas workflows, and signed multi-architecture releases.