refactor(ingest): doc legacy ocr queue; fix docstrings + getattr guard

Address claude-review round 2 on #922:

- Legacy `ingest-ocr` tier resolution (important 1): document why it deliberately
  resolves to `fast` rather than mapping to `ocr-upstream` — stranded pre-split
  jobs re-extract empty and re-escalate via the ladder to the cheap
  `ocr-incluster` rung, keeping them OFF the paid upstream rung. Added a
  tier_for_queue(LEGACY_INGEST_QUEUE_OCR) == "fast" assertion.
- Double get_settings() in `_get_batch_client` (important 2): bind once to a local.
- Stale docstrings (important 3): OcrProcessor (serves both rungs now),
  _tier_available (both OCR rungs gated), evaluate_escalation (targets
  ocr-incluster, falls through to ocr-upstream).
- Misconfigured model_setting (nit 5): OcrProcessor.__init__ raises ValueError on
  an unknown settings attr (fail-fast at startup vs AttributeError mid-OCR); also
  removes the dynamic-getattr static-analysis smell SonarCloud flagged.
- Redundant guard (nit 4): kept `and ocr_tier is not None` — it's required for ty
  to narrow ocr_tier to str for record_document_escalation; added a comment.
- Test gap (nit 6): added a test pinning the CURRENT incluster-failure ->
  tier-1 fallback (does NOT cascade to upstream) so the future 503-escalation
  change is an explicit diff.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-06-18 00:16:20 +02:00
co-authored by Claude Opus 4.8
parent 87b8edd139
commit 6e32bd9561
5 changed files with 55 additions and 8 deletions
+20
View File
@@ -803,6 +803,26 @@ async def test_inline_incluster_disabled_skips_to_upstream(monkeypatch):
esc.assert_called_once_with("fast", "ocr-upstream", "empty_text")
async def test_inline_incluster_failure_falls_back_to_fast_not_upstream(monkeypatch):
"""CURRENT behavior (pins the known follow-up gap): when the chosen in-cluster
rung runs but FAILS (e.g. GPU 503 -> success=False), the inline path keeps the
tier-1 result rather than cascading to the paid upstream rung. OCR is an
enhancement, not a gate. (A future change will escalate transient GPU failures
to ocr-upstream; this test makes that diff explicit.)"""
monkeypatch.setattr(
reg_mod, "get_settings", lambda: _Settings(ocr=True, ocr_incluster=True)
)
monkeypatch.setattr(reg_mod, "record_document_escalation", MagicMock())
r = _registry(
(_Fake("fast", "fast", text=""), 20),
(_Fake("ocr-incluster", "ocr-incluster", text="", success=False), 6),
(_Fake("ocr-upstream", "ocr-upstream", text="upstream ocr text"), 5),
)
res = await r.process(b"%PDF-1.7", "application/pdf")
assert res.processor == "fast"
assert res.success is True
def _empty_result() -> ProcessingResult:
return ProcessingResult(
text="",
@@ -51,6 +51,10 @@ class TestLadder:
# Legacy / unknown / None all fall back to the cheapest tier.
assert pq.tier_for_queue(pq.LEGACY_INGEST_QUEUE) == "fast"
assert pq.tier_for_queue(None) == "fast"
# The pre-split legacy OCR queue also resolves to fast (NOT ocr-upstream):
# stranded in-flight jobs re-extract empty and re-escalate via the ladder
# to the cheap ocr-incluster rung, never straight to paid upstream.
assert pq.tier_for_queue(pq.LEGACY_INGEST_QUEUE_OCR) == "fast"
class TestTieredEscalationStrategy: