pkgs/academic-ocr-drain/ was retargeted to Halogen Flash on the worker in f32289c (2026-09-11): default.nix:43-51 generates INFERENCE_URL defaulting to http://worker:8731. Two things in the request path were not retargeted with it. Both are measured below against the running 0.7.0 server.
1. The request never sets a thinking control, so every page reasons at xhigh
vlm.sh:15-20 builds the body with model, temperature: 0, max_tokens: 16384 and the messages, and nothing else.
MEASURED 2026-09-19, curl http://worker:8731/health:
reasoning_effort_default: "xhigh"
token_budget_covers_reasoning: true
supported: [..., "enable_thinking", "reasoning_effort", "preserve_thinking", ...]
So a request that omits the field takes the server default and reasons at xhigh before it transcribes, out of the same 16,384-token budget that has to hold the page. A recorded vision run on this server (notes/references/devlogs/2h26/huion-notepad-pipeline/huion/ocr/runs/halogen-vanilla-2026-09-14/p01-metadata.json) spent 443 of 650 completion tokens on reasoning, so about two thirds of the budget went to thinking on a handwriting page with 56 words on it.
vlm.sh:25 rejects finish_reason=length outright, which is correct and is the point: a page that reasons its way into the cap is discarded after paying for the whole generation.
MEASURED tonight with enable_thinking: false on a 10-column regression table rendered at 150 dpi:
|
value |
| reasoning tokens |
0 |
| completion tokens |
893 |
| finish reason |
stop |
| elapsed |
41.8 s |
The transcription was correct, including the significance stars that the PDF text layer renders as the mojibake úúú. Thinking off is enough for this work.
Fix: add enable_thinking: false to the body in vlm.sh. The server's own rule is "a field the request sends always wins; a default fills only a field the request omits", so one field settles it. This is also the standing default already written down for FRONT-07 (notes/references/continuity/2026-09-16-orchestration-day/.../menial-rulings.md F14 Q4, "orchestrator may default").
2. Renders are made at 200 dpi, which is above the server's pixel cap
drain.sh sets dpi: 200 in the flow args and raster.sh takes the dpi as an argument.
MEASURED, /health:
vision.max_pixels: 3686400
vision.size_multiple: 32
vision.input: "data: URL or bare base64 in an image content part; http(s) URLs are refused"
US Letter at 200 dpi is 1700 x 2200 = 3,740,000 px and A4 is 1654 x 2339 = 3,868,706 px. Both are over the cap. The health report does not say whether the frontend refuses such an image or silently downsizes it, and the answer matters: a silent downsize makes the effective resolution unpredictable per page size, and a refusal fails the page.
MEASURED at 150 dpi on two real pages from the corpus:
| page |
render |
pixels |
under cap |
| A4 journal page |
1240 x 1754 |
2,176,714 |
yes |
| US Letter handout |
1275 x 1650 |
2,103,750 |
yes |
Fix: compute the dpi per page from its media box so the render lands under max_pixels, and step it down rather than fail if it does not. 150 dpi clears both common page sizes with room to spare; a runner that wants a fixed number should use 150, not 200.
3. While this file is open
mech.sh calls mutool draw for its second mechanical extraction. mupdf-headless is in the package closure so the store build is fine, but there is no mutool on the coordinator's login PATH (MEASURED), so nothing outside the wrapper can reproduce the mech gate. Worth a line in the README if the gate is ever meant to be run by hand.
Context
This is the engine half of reviving the academic OCR drain. The corpus is intact on the NAS (/mnt/nas/documents/academic-papers, 3,367 PDFs, 8.1 GB) and the completion join against notes is 1,880 papers done, 1,467 pending, 156,811 pending pages (MEASURED 2026-09-19). The drain itself last wrote on 2026-08-09 and stopped on its own free-space floor.
pkgs/academic-ocr-drain/was retargeted to Halogen Flash on the worker in f32289c (2026-09-11):default.nix:43-51generatesINFERENCE_URLdefaulting tohttp://worker:8731. Two things in the request path were not retargeted with it. Both are measured below against the running 0.7.0 server.1. The request never sets a thinking control, so every page reasons at xhigh
vlm.sh:15-20builds the body withmodel,temperature: 0,max_tokens: 16384and the messages, and nothing else.MEASURED 2026-09-19,
curl http://worker:8731/health:So a request that omits the field takes the server default and reasons at xhigh before it transcribes, out of the same 16,384-token budget that has to hold the page. A recorded vision run on this server (
notes/references/devlogs/2h26/huion-notepad-pipeline/huion/ocr/runs/halogen-vanilla-2026-09-14/p01-metadata.json) spent 443 of 650 completion tokens on reasoning, so about two thirds of the budget went to thinking on a handwriting page with 56 words on it.vlm.sh:25rejectsfinish_reason=lengthoutright, which is correct and is the point: a page that reasons its way into the cap is discarded after paying for the whole generation.MEASURED tonight with
enable_thinking: falseon a 10-column regression table rendered at 150 dpi:The transcription was correct, including the significance stars that the PDF text layer renders as the mojibake
úúú. Thinking off is enough for this work.Fix: add
enable_thinking: falseto the body invlm.sh. The server's own rule is"a field the request sends always wins; a default fills only a field the request omits", so one field settles it. This is also the standing default already written down for FRONT-07 (notes/references/continuity/2026-09-16-orchestration-day/.../menial-rulings.mdF14 Q4, "orchestrator may default").2. Renders are made at 200 dpi, which is above the server's pixel cap
drain.shsetsdpi: 200in the flow args andraster.shtakes the dpi as an argument.MEASURED,
/health:US Letter at 200 dpi is 1700 x 2200 = 3,740,000 px and A4 is 1654 x 2339 = 3,868,706 px. Both are over the cap. The health report does not say whether the frontend refuses such an image or silently downsizes it, and the answer matters: a silent downsize makes the effective resolution unpredictable per page size, and a refusal fails the page.
MEASURED at 150 dpi on two real pages from the corpus:
Fix: compute the dpi per page from its media box so the render lands under
max_pixels, and step it down rather than fail if it does not. 150 dpi clears both common page sizes with room to spare; a runner that wants a fixed number should use 150, not 200.3. While this file is open
mech.shcallsmutool drawfor its second mechanical extraction.mupdf-headlessis in the package closure so the store build is fine, but there is nomutoolon the coordinator's login PATH (MEASURED), so nothing outside the wrapper can reproduce the mech gate. Worth a line in the README if the gate is ever meant to be run by hand.Context
This is the engine half of reviving the academic OCR drain. The corpus is intact on the NAS (
/mnt/nas/documents/academic-papers, 3,367 PDFs, 8.1 GB) and the completion join against notes is 1,880 papers done, 1,467 pending, 156,811 pending pages (MEASURED 2026-09-19). The drain itself last wrote on 2026-08-09 and stopped on its own free-space floor.