fix(ocr): review pass — min-ada floor regression test, auth-before-parse, failure-path reconciliation, disclosure label coverage

Fixes 2 critical, 2 important, and 5 minor findings from review of 069edcb:

- C1: add a happy-path test that reaches postOcrEscrow.ts's escrowLockFloor
  call and asserts the locked amount; verified it fails against a bare
  economicTotal and passes against the real code.
- C2: gate /v1/ocr/extract (auth + rate limits) before the 16mb body parser
  so an unauthenticated caller can no longer force a full buffer/JSON.parse.
- I2: hoist result/used/escrowRef in the OCR one-shot handler so the failure
  path records escrow_ref/supplier/cost when an escrow was actually posted,
  and emit an ocr_failed structured log line mirroring ocr_settled.
- I3: export venueAttribution and cover its sanitization directly; add a
  stubbed happy-path route test asserting the first-party-brokered
  disclosure label reaches the response.
- Minor: drop unused hfWeightsSource end to end, rename a misleading test,
  make the OCR capability template's pinning language conditional on the
  self-hosted upstream, tighten the /v1/ocr path-prefix guard, and make
  preflight's required_lovelace use the same escrowLockFloor the builder
  locks (exported from the shared tx barrel for gateway use).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
FilipBl4gojevic
2026-08-10 17:12:12 +02:00
parent 069edcb076
commit 2b2295b7ed
13 changed files with 326 additions and 51 deletions

View File

@@ -52,7 +52,6 @@ OPENAI_TIMEOUT_MS=120000 # page inference is seconds; keep < advert max
# openai-vision upstream only (attestation upgrade path):
# OCR_PROMPT_OVERRIDE= # exact serving prompt, pinned at integration
# HF_MODEL_REVISION= # 40-hex checkpoint SHA; mismatch refuses Claim
# HF_WEIGHTS_SOURCE=hf:datalab-to/chandra-ocr-2
# REVISION_PROBE_URL= # e.g. http://chandra-vllm:8000/info
# ── Service ───────────────────────────────────────────────────────────────

View File

@@ -1,7 +1,7 @@
{
"capability_id": "ocr.page.extract.chandra-ocr-2.v1",
"weights_source": "hf:datalab-to/chandra-ocr-2",
"model_revision": "<40-hex commit SHA pinned at endpoint provisioning>",
"model_revision": "<40-hex commit SHA; self-hosted (OCR_UPSTREAM=openai-vision) deployments only — the Datalab-hosted default (OCR_UPSTREAM=datalab) is a third-party API with no pinnable checkpoint, so this is unset there>",
"license": "modified OpenRAIL-M (weights); Apache-2.0 (code)",
"request_shape": {
"route": "POST /v1/ocr/extract",
@@ -14,8 +14,8 @@
"verify": "GET /capability → pub_key_hex; verify signature over canonical(receipt)"
},
"revision_probe": {
"route": "<runtime info route reporting the loaded checkpoint>",
"policy": "probe before every Claim; mismatch refuses the job"
"route": "<runtime info route reporting the loaded checkpoint; self-hosted (openai-vision) upstream only>",
"policy": "self-hosted (OCR_UPSTREAM=openai-vision) upstream: probe before every Claim, mismatch refuses the job. Datalab-hosted default (OCR_UPSTREAM=datalab): per-job liveness probe only, no checkpoint pin."
},
"operator_disclosure": "first-party (HAL8-operated supplier)"
}

View File

@@ -165,12 +165,6 @@ export interface SupplierConfig {
* Env: HF_MODEL_REVISION. "" = no pin.
*/
hfModelRevision: string;
/**
* Hub identity of the served weights, e.g. "hf:datalab-to/chandra-ocr-2".
* Recorded for telemetry now; feeds the receipt extension when that
* schema is added. Env: HF_WEIGHTS_SOURCE. "" = unset.
*/
hfWeightsSource: string;
/**
* Serving-runtime info route reporting the loaded checkpoint (TGI-style
* /info or vLLM equivalent). Env: REVISION_PROBE_URL. "" = probing off.
@@ -422,7 +416,6 @@ export function loadConfig(env: Record<string, string | undefined>): SupplierCon
if (hfModelRevision !== "" && !/^[0-9a-fA-F]{40}$/.test(hfModelRevision)) {
throw new Error("loadConfig: HF_MODEL_REVISION must be a 40-hex commit SHA when set");
}
const hfWeightsSource = env.HF_WEIGHTS_SOURCE ?? "";
const revisionProbeUrl = env.REVISION_PROBE_URL ?? "";
// Datalab upstream: the health route is derived from DATALAB_BASE_URL, so
// the liveness probe defaults ON without a REVISION_PROBE_URL. The
@@ -489,7 +482,6 @@ export function loadConfig(env: Record<string, string | undefined>): SupplierCon
datalabTimeoutMs,
ocrPromptOverride,
hfModelRevision,
hfWeightsSource,
revisionProbeUrl,
revisionProbeMode,
liveChain,

View File

@@ -1385,7 +1385,7 @@ export function createApp(deps: SupplierDeps): Application {
// below; every other route keeps the 1mb ceiling.
const jsonBody = express.json({ limit: "1mb" });
app.use((req, res, next) =>
req.path.startsWith("/v1/ocr") ? next() : jsonBody(req, res, next));
req.path.startsWith("/v1/ocr/") ? next() : jsonBody(req, res, next));
// /healthz is mounted FIRST and uses no deps — it must succeed regardless
// of chain/state/config (independent of /status free/working/offline).