fix(ocr): wire batch settings into _field_map + review nits

Round 1 review (PR #910):
- BLOCKING: add document_ocr_mode / _batch_poll_seconds / _batch_max_wait_seconds
  to config._field_map — without it dynaconf silently ignored the env vars and
  DOCUMENT_OCR_MODE=batch could never be enabled in production. Add a regression
  test asserting the three round-trip from env.
- migration 008: give batch_ocr_jobs a composite PRIMARY KEY on
  (user_id, doc_id, doc_type, etag) instead of a bare UniqueConstraint (N1).
- OcrProcessor: use a dedicated _batch_client_lock instead of sharing the sync
  backend lock (N3).
- tests: use https:// gateway URLs in the new fixtures to clear SonarCloud's
  "insecure http" security hotspots (all 14 were test-only http://gw literals).

1653 unit tests pass; ruff + ty green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-06-15 10:36:44 +02:00
co-authored by Claude Opus 4.8
parent 3b7e8d779b
commit 2b7dfc8535
6 changed files with 48 additions and 24 deletions
@@ -36,7 +36,11 @@ def upgrade() -> None:
# Document identity (the same keys the OCR tier receives via the
# processor ``options``). ``etag`` is the content-version key: a changed
# document (new etag) is a new job, so a stale row never serves results
# for the wrong content.
# for the wrong content. The four-column natural key IS the primary key:
# one in-flight job per (document, content version), and the PK doubles as
# the unique index ``insert_pending``'s ON CONFLICT target relies on. A
# resubmit for a new etag inserts a new row; the superseded row is swept on
# resubmit (delete_stale_for_doc).
sa.Column("user_id", sa.Text(), nullable=False),
sa.Column("doc_id", sa.Text(), nullable=False),
sa.Column("doc_type", sa.Text(), nullable=False),
@@ -51,14 +55,8 @@ def upgrade() -> None:
# (DOCUMENT_OCR_BATCH_MAX_WAIT_SECONDS).
sa.Column("submitted_at", sa.BigInteger(), nullable=False),
sa.Column("updated_at", sa.BigInteger(), nullable=False),
# One in-flight job per (document, content version). A resubmit for a new
# etag inserts a new row; the superseded row is swept on resubmit.
sa.UniqueConstraint(
"user_id",
"doc_id",
"doc_type",
"etag",
name="uq_batch_ocr_jobs_doc",
sa.PrimaryKeyConstraint(
"user_id", "doc_id", "doc_type", "etag", name="pk_batch_ocr_jobs"
),
)