Files
0pt/docs/guides/document-workbench.md
admin 525bf6b9a0
CI (SIAX Cloud) / sonar (pull_request) Skipped
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
masterplan-lock / check (pull_request) Successful in 3s
masterplan-lock / check (push) Successful in 5s
Security Scan (SIAX Cloud) / security (push) Successful in 15s
CI (SIAX Cloud) / security (pull_request) Successful in 22s
CI (SIAX Cloud) / security (push) Successful in 23s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 23s
CI (SIAX Cloud) / integration (pull_request) Successful in 30s
CI (SIAX Cloud) / quality (push) Successful in 45s
CI (SIAX Cloud) / quality (pull_request) Successful in 1m18s
feat(workbench): use the decision server's local model while the AI API is on hold
- DecisionOllamaGatewayClient calls the self-hosted Ollama on
  server-decision-01 (tailnet HTTP only for loopback/RFC1918/100.64-127),
  keeps the same local admission and reports providerKind=local.
- createInf0Gateway prefers it over INF0/LiteLLM when configured.
- Evidence is computed deterministically from values when a small model omits
  offsets; a value must occur exactly once in the source or the result goes to
  review. This makes a 9B local model usable without weakening verification.

Tests: 4 new gateway cases + 2 evidence-derivation cases; full typecheck green.
2026-11-02 17:09:42 +01:00

4.5 KiB

Document workbench — upload → structure → validated export

The customer-facing slice that turns an uploaded file into evidence-bound data.

Routes

Route Purpose Fails closed with
POST /api/0pt/documents/upload multipart upload of the original bytes into DOC0, recorded in a durable attempt journal before dispatch 503 DOC0_NOT_CONFIGURED, 503 PROJECT_AUTHORIZATION_NOT_CONFIGURED, 503 UPLOAD_JOURNAL_NOT_CONFIGURED
POST /api/0pt/documents/structure re-reads the DOC0 segment index, calls INF0, validates every field against an exact source span, reserves/settles credits 503 WORKBENCH_NOT_CONFIGURED, 503 MODEL_POLICY_NOT_CONFIGURED, 503 CREDITS_NOT_CONFIGURED, 402 INSUFFICIENT_CREDITS
GET /api/0pt/documents/models the server-approved model routes and limits 503 MODEL_POLICY_NOT_CONFIGURED
GET /api/0pt/credits/balance tenant credit balance 503 CREDITS_NOT_CONFIGURED
GET /api/0pt/credits/packs sellable packs from the server-owned price book 503 PRICE_BOOK_NOT_CONFIGURED
POST /api/0pt/credits/checkout Stripe Checkout session + server price snapshot 503 PRICE_BOOK_NOT_CONFIGURED, 503 STRIPE_NOT_CONFIGURED
POST /api/webhooks/stripe re-reads the session and payment intent, then grants credits idempotently non-2xx until processed

UI: /portal/dokument (upload, structure, review, download) and /portal/krediter (balance, packs, checkout). The portal signs in through Zitadel OIDC (/api/auth/login → /api/auth/callback); the resulting signed session cookie is accepted by middleware as a verified principal (Bearer still wins).

Invariants

  1. Tenant and actor come only from middleware's verified headers. A customer route never trusts tenant_id/actor_id from the body.
  2. Project access is checked by OpenFGA (@siax/access), the same primitive DOC0 uses. Until the central relationship store is deployed, an explicit server-owned grant list (OPT_PROJECT_GRANTS) can be used instead. Unconfigured or unavailable means denied, never allowed.
  3. The model never sees unverified text. Doc0SourceClient verifies version, tenant, checksum, segment hashes and that the index was not truncated before anything is sent to INF0.
  4. Every returned value must point at an exact span in the source; otherwise the result is needs_review and nothing is exported.
  5. Credits are reserved before the model runs and settled to measured usage. An unknown model outcome keeps the reservation for reconciliation instead of releasing it.
  6. No price is ever read from the client. The price book is a versioned, server-owned JSON document (OPT_CREDIT_PRICE_BOOK).
  7. Pilot mode is explicit. OPT_CREDITS_MODE=off skips reserve/settle and reports credits: null. It is not a silent fallback and it does not enable purchases; unset/on requires the price book and the ledger.

Reusable packages

  • packages/siax-access (@siax/access) — framework-neutral OpenFGA relationship checks and a fail-closed isProjectAccessAllowed. Intended for DOC0, N0D and every other SIAX product instead of per-repo copies of project-relationships.ts.
  • src/document-workbench/* — upload coordination, DOC0 source reading, INF0 admission, structured-output validation, export and credit ledger. These modules have no Next.js imports and can be lifted into a published package unchanged.

Which AI path is used

Order:

  1. Decision server model (DECISION_OLLAMA_URL + DECISION_OLLAMA_MODEL) — the self-hosted Ollama on server-decision-01, used while the external model API is on hold. Internal only, no provider key, no per-token cost.
  2. Live LiteLLM gateway (INF0_GATEWAY_LITELLM_KEY).
  3. Native INF0_URL surface.

Admission — tenant/project scope, model allow-list, data class, external-transfer policy and token limits — runs locally in every path before the request leaves the process. Evidence spans are computed deterministically from the returned values when a small local model omits offsets: a value must occur exactly once in the source, otherwise the result is needs_review.

What is still deliberately not claimed

  • The output is mechanically_validated, not proven complete or semantically correct. OCR quality and coverage require review.
  • Refunds and chargebacks do not automatically revoke credits; no such handler is wired.
  • Format breadth is limited by DOC0's parser. A file DOC0 cannot parse is reported, never guessed.