fix(documents): bound an extraction that runs inside the request

Without Prefer: respond-async the extract route ran the read with no
schedule, so a twenty-page report read a page at a time, with a retry
each, could make forty model calls in one HTTP request. The iPhone app
sends no Prefer header and reads the document detail from the answer,
so the request keeps its 200 and its body.

An extraction without a run deadline now plans at most three reads (six
calls): a longer document has its pages or text shared out between
them, and what does not fit is reported as extractionIncomplete on the
document. The background run keeps reading it a page at a time.

Refs #1257
This commit is contained in:
Marc-André Bombeck committed 2026-10-25 01:01:13 +02:00
1 parent 958d230b9f
commit c9481b672c
5 files changed
+100 -18

No files matched your search

@@ -30,9 +30,13 @@
* answered here, then the route answers 202 with a run id. The run's result is
* `{ documentId, factsStaged, status }` rather than the whole detail (the
* facts are staged on the document; the client reads them from there).
* Without the header the route behaves exactly as before; the iPhone app
* relies on that. Both paths run one body (`executeDocumentExtract`), which
* re-checks the document under a row lock before it stages anything.
* Without the header the route answers the document detail as before; the
* iPhone app relies on that. Both paths run one body (`executeDocumentExtract`),
* which re-checks the document under a row lock before it stages anything.
* Inside the request the reads are bounded (`SYNC_EXTRACT_MAX_READS`): a
* twenty-page report read a page at a time with a retry each was forty model
* calls in one HTTP request. What does not fit is reported on the document as
* `extractionIncomplete`, and the background run reads it in full.
*/
import { Buffer } from "node:buffer";