think
16px
820px

Task 9 — Packaging, example config, docs, Job API smoke (P2 exit)

Branch: feat/gateway-p2-jobs-ocr · Base HEAD: b8661b1

What was added

1. Example config — deploy/gateway.example.yaml

Three job-typed upstreams appended (existing LLM/embedding upstreams kept intact):

id type adapter operation models api_key_env submit_path slots
paddleocr ocr-http sync-http ocr paddleocr /predict total 4 / batch 4
azure-di ocr-http azure-di ocr azure-di-layout-v4, azure-di-read-v4 AZURE_DI_KEY …prebuilt-layout:analyze?api-version=… (+ poll_path) total 2 / batch 2
doc-classifier classify classify classify doc-classifier /classify total 4 / batch 2

All class: on_prem. The azure-di entry carries the Task-5 caveat comment: DI returns an absolute
Operation-Location; its host/scheme may not be reachable as-is on an on-prem/proxied DI and must be
normalized to endpoints[0] / poll_path at deploy. config.Load accepts the file (verified: 7 upstreams
parse, adapter/operation/slots resolved correctly).

2. README — README.md

New Job API section: POST /jobs (single + fan-out envelope) with the full header table
(X-Tenant-Id/Surface/User-Id/Request-Id/Priority/Idempotency-Key/X-Doc-Hash/X-Doc-Pages), GET /jobs/{id}
with queued (queue_position/eta_ms) vs processing (stage/progress) vs completed/failed fields,
idempotency + JOB_UNKNOWN-resubmit semantics, fan-out max_parallel, and the note that the Job API only
activates when a ocr-http/classify upstream is configured. Plus a Deploy-time live-fire checklist
(see below) and pointers to both smoke entry points.
Upload: https://x056.think.val.id/README.md

3. Smoke — Go integration test + deploy bash script

Chosen approach: a Go integration test as the reliably-runnable-here smoke, plus a bash script for deploy-time.

  • internal/server/jobs_smoke_test.goTestJobAPISmoke (GREEN, -race): wires the REAL server mux +
    EnableJobs (LocalStore + real SyncHTTPAdapter) against a local echo stub ocr-http upstream — no
    real PaddleOCR/Azure-DI needed. Asserts:
    1. POST /jobs (with Idempotency-Key) → 202 queued, then polls to completed and verifies the stub's
    result body is returned verbatim; upstream hit exactly once.
    2. Resubmit same (tenant, Idempotency-Key)same job_id, upstream still hit exactly once (no dup run).
    3. GET /jobs/{unknown}404 {code:"JOB_UNKNOWN"}.
  • scripts/jobs_smoke.sh (matches P0 smoke.sh style): deploy-time drill against a running gateway with
    a live job upstream — submit→poll→completed, idempotent resubmit (same job_id), JOB_UNKNOWN 404. bash -n clean.

4. CONVENTIONS.md — untouched (intentional)

The Job API contract engines rely on (JOB_UNKNOWN, queued-vs-processing clock, idempotency-resubmit) is
already in v1.0 §3/§4. Adapter names and submit_path are engine-invisible gateway config, not part of the
cross-service contract, so no clarification / version bump is warranted per the file's own rule.

Gate results

  • go build ./... — OK
  • go vet ./... — OK
  • go test -race ./internal/jobs/ ./internal/server/ — ok (jobs 4.1s, server 2.0s)
  • go test ./... — all packages ok

Deploy-time live-fire checklist (NOT run here — no real upstreams reachable from the dev box)

Documented in README under "Deploy-time live-fire checklist":
- PaddleOCR reachability: paddleocr endpoint + /predict answers from the gateway container; a real doc
round-trips to completed (scripts/jobs_smoke.sh MODEL=paddleocr).
- Azure-DI Operation-Location normalization: confirm the returned absolute URL's host/scheme is reachable
from the gateway (or normalize to endpoints[0]/poll_path); verify AZURE_DI_KEY set.
- doc-classifier /classify reachability; interactive-priority submissions complete quickly.
- Audit: an OCR job emits an event on ahu.ai.audit with operation=ocr + doc_hash (redis-cli XLEN ahu.ai.audit).

Concerns

  • The example paddleocr/azure-di/doc-classifier endpoints (ports 8010/8011/8012 on 192.168.83.20) are
    placeholders — real ports must be set at deploy (the GPU-host survey lists ahu-classifier as loopback-bound).
  • Azure-DI submit_path hardcodes prebuilt-layout + api-version; multi-model DI use (e.g. azure-di-read-v4)
    may need the model id templated into the path at deploy rather than a fixed submit_path.
  • The bash scripts/jobs_smoke.sh cannot be exercised on the dev box (no live upstream); its logic mirrors the
    green Go test.