收敛真实OCR样票验收入口(07-28-travel-reimbursement-guide)
这个提交包含在:
@@ -251,6 +251,103 @@ const persisted = sanitizeOcrResultForPersistence("tencent", normalized);
|
||||
await prisma.ocrResult.create({ data: { result_json: persisted } });
|
||||
```
|
||||
|
||||
## Scenario: Live OCR Sample Stdin Probe
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
- Trigger: an authorized real PDF must prove Tencent credentials, network,
|
||||
subtype normalization and required-field behavior without creating an OA
|
||||
invoice or persisting the sample on the execution host.
|
||||
- This probe is intentionally one-file and PDF-only. It does not retain the
|
||||
historical manifest, directory scan, image evaluation or legacy VAT-only
|
||||
command modes.
|
||||
|
||||
### 2. Signatures
|
||||
|
||||
- Command:
|
||||
`node scripts/qa/check-ocr-provider-samples.mjs --alias=SAMPLE-PDF-<SAFE_ALIAS>`.
|
||||
- Input: exactly one PDF on stdin, at most `OCR_PDF_MAX_BYTES` (7 MiB).
|
||||
- Runtime env: `TENCENT_SECRET_ID`, `TENCENT_SECRET_KEY`, optional
|
||||
`TENCENT_OCR_REGION` and `OCR_TIMEOUT_MS`; provider is fixed to `tencent`.
|
||||
- Provider boundary: `runOcrForInvoice({ config, ocrType: "vat",
|
||||
imageBase64, sourceMimeType: "application/pdf" })`.
|
||||
- Output: one JSON object containing only `alias`, `provider`, `status`,
|
||||
`transportMode`, `elapsedMs`, safe document category/subtype/count,
|
||||
per-field hit booleans, missing field names and a bounded error code.
|
||||
|
||||
### 3. Contracts
|
||||
|
||||
- The caller selects one authorized PDF explicitly and streams it through
|
||||
stdin. The probe never accepts a file path, directory, manifest, image or
|
||||
batch list and never writes sample bytes to disk, OA storage or the database.
|
||||
- Alias must match `SAMPLE-PDF-[A-Z0-9_-]+`; it replaces the original file name
|
||||
in every output and evidence record.
|
||||
- Validate the 7 MiB limit, PDF version header and terminal `%%EOF` before
|
||||
constructing Base64 or invoking Tencent. One process performs at most one
|
||||
provider call.
|
||||
- Reuse `RecognizeGeneralInvoice`, `sanitizeOcrResultForPersistence` and the
|
||||
production category-specific required-field rules. The probe must not carry
|
||||
a parallel VAT-only field list.
|
||||
- Never output recognized identifiers, dates, amounts, buyer/seller/passenger
|
||||
names, provider messages, raw response or input bytes. Field presence is a
|
||||
boolean; errors are bounded stable codes.
|
||||
- A PASS proves the direct provider/normalization path only. It does not prove
|
||||
OA upload, queue, persistence, duplicate detection, binding or reimbursement
|
||||
submission.
|
||||
|
||||
### 4. Validation & Error Matrix
|
||||
|
||||
- Missing/invalid alias -> `sample_alias_invalid`; no provider call.
|
||||
- Empty stdin -> `sample_empty`; no provider call.
|
||||
- More than 7 MiB -> `sample_too_large`; stop reading and do not call provider.
|
||||
- Invalid header or missing terminal EOF -> `sample_pdf_invalid`; no provider
|
||||
call.
|
||||
- Missing credentials or provider mismatch -> `ocr_credentials_missing` /
|
||||
`ocr_provider_invalid`; no business values in output.
|
||||
- Supported subtype with missing category-required fields -> `status=HOLD`
|
||||
plus field names only.
|
||||
- Tencent failure -> `status=HOLD` plus a bounded SDK error code; omit the
|
||||
provider message and raw error object.
|
||||
|
||||
### 5. Good/Base/Bad Cases
|
||||
|
||||
- Good: stream one railway electronic ticket using an anonymous alias; receive
|
||||
`electronic_train_ticket`, boolean field hits and no recognized values or
|
||||
persisted sample.
|
||||
- Base: stream one supported accommodation invoice and receive a PASS summary
|
||||
for its VAT/full-VAT category.
|
||||
- Bad: point the probe at a directory, auto-run every PDF, write a manifest with
|
||||
real paths, accept images, print OCR values or retain the sample remotely.
|
||||
|
||||
### 6. Tests Required
|
||||
|
||||
- Unit tests inject synthetic provider results for VAT, full VAT and railway
|
||||
categories and assert category-aware required fields.
|
||||
- Negative tests assert non-PDF, truncated PDF and oversized input fail before
|
||||
the provider mock is called.
|
||||
- Privacy tests seed raw provider and recognizable normalized markers, then
|
||||
assert serialized output contains only booleans and safe metadata.
|
||||
- CLI test pipes one synthetic PDF over stdin with credentials absent and
|
||||
asserts one parseable redacted error object with empty stderr.
|
||||
- Before deployment run `node --check`, the focused tests, full backend tests,
|
||||
sensitive-content scan, task validation and Trellis governance.
|
||||
|
||||
### 7. Wrong vs Correct
|
||||
|
||||
#### Wrong
|
||||
|
||||
```bash
|
||||
PLAYWRIGHT_OCR_LIVE_DIR=<sample-dir> \
|
||||
node scripts/qa/check-ocr-provider-samples.mjs --provider=tencent --json
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```bash
|
||||
node scripts/qa/check-ocr-provider-samples.mjs \
|
||||
--alias=SAMPLE-PDF-TRAIN < <authorized-single-sample.pdf>
|
||||
```
|
||||
|
||||
## Scenario: Payment Batch Receipt Attention Count
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
在新工单中引用
屏蔽一个用户