> ## Documentation Index
> Fetch the complete documentation index at: https://docs.payfi.global/llms.txt
> Use this file to discover all available pages before exploring further.

# MVP Analysis Engine

> Final execution specification for the PayFi Analysis Engine MVP on Railway n8n.

This guide is the implementation contract for the MVP Analysis Engine.

The MVP delivers document requirements, secure upload, per-document analysis, deterministic operation scoring, a persisted Decision Pack, signed redacted webhooks, and mandatory human review.

The MVP does not deliver automatic operation approval, automatic regulatory submission, legal fine-tuning, autonomous sanctions/PEP decisions, or n8n as a system of record.

## Source of truth

| Component             | Role                                                                                                                                                       |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Railway n8n           | Source of truth for published workflows and active workflow topology.                                                                                      |
| Postgres              | System of record for operations, states, documents, analyses, Decision Packs, policies, corpus versions, audit logs, timeline, webhooks, and human review. |
| Brazil object storage | Temporary source for raw uploaded documents.                                                                                                               |
| pgvector/vector index | Retrieval index only; not the primary source for decisions.                                                                                                |
| n8n executions        | Operational evidence only; not primary audit storage.                                                                                                      |

n8n must not store final decisions, raw documents, active policy, approved corpus, or primary audit history. The API/worker validates n8n JSON before persisting business state.

## Railway workflows

| Workflow                        | ID                 | Active | Contract                                                                          |
| ------------------------------- | ------------------ | -----: | --------------------------------------------------------------------------------- |
| PayFi Document Requirements     | `PAYFIDOCREQ1`     |    yes | Returns document requirements and `processingTraceEvents`.                        |
| Payfi Compliance Pipeline P0+P1 | `ZMlinKAKU3uUG9b8` |    yes | Per-document analysis.                                                            |
| PayFi Risk Policy Processing    | `PAYFIRISKPOL1`    |     no | Excluded from the demo until it has a real integration and validated v2 contract. |
| PayFi Operation Decision Engine | `Rsmrc2p5STzykAWj` |    yes | Operation-level Decision Pack.                                                    |

The operation decision workflow receives `operationFacts`, `approvedRequirements`, `approvedRequirementAssessment`, `documents`, `documentAnalyses`, `activePolicy`, `regulatoryCorpusVersion`, `rulesVersion`, `modelProfile`, and `traceContext`.

It returns the closed contract-v2 Decision Pack schema and echoes the exact input snapshot hash. If a conclusion lacks a source, it returns a not-determined or review-required outcome with an absence reason; it must not invent a regulatory conclusion or score through missing evidence.

## State machine

The repo keeps backward-compatible public states and maps the closure spec as follows:

| Closure state               | Repo state                                      |
| --------------------------- | ----------------------------------------------- |
| `REQUIREMENTS_RUNNING`      | `REQUIREMENTS_PENDING`                          |
| `REQUIREMENTS_READY`        | `REQUIREMENTS_REVIEW_REQUIRED`                  |
| `REQUIREMENTS_APPROVED`     | `AWAITING_DOCUMENTS` with approved requirements |
| `DOCUMENT_ANALYSIS_RUNNING` | `PROCESSING`                                    |
| `DOCUMENT_ANALYSIS_FAILED`  | `PROCESSING_FAILED`                             |
| `DECISION_ENGINE_RUNNING`   | `PROCESSING` with decision trace event          |
| `DECISION_PACK_READY`       | persisted `operation_decision_packs` row        |
| `APPROVED_BY_HUMAN`         | `MANUAL_REVIEW_APPROVED`                        |
| `REJECTED_BY_HUMAN`         | `MANUAL_REVIEW_REJECTED`                        |
| `REQUESTED_CHANGES`         | `MANUAL_REVIEW_CHANGES_REQUESTED`               |
| `ERROR`                     | `FAILED` or workflow-specific failed state      |

Allowed MVP transitions:

| From                           | To                                | Trigger                         | Owner        | Mode             | Side effects                                               |
| ------------------------------ | --------------------------------- | ------------------------------- | ------------ | ---------------- | ---------------------------------------------------------- |
| `CREATED`                      | `REQUIREMENTS_PENDING`            | operation created               | API          | automatic        | operation row, timeline, webhook                           |
| `REQUIREMENTS_PENDING`         | `REQUIREMENTS_REVIEW_REQUIRED`    | requirements completed          | worker/n8n   | automatic        | assessment persisted, timeline, webhook                    |
| `REQUIREMENTS_PENDING`         | `AWAITING_DOCUMENTS`              | requirements auto-confirmed     | worker       | automatic        | document requirements approved only; no operation approval |
| `REQUIREMENTS_PENDING`         | `REQUIREMENTS_FAILED`             | requirements final failure      | worker       | automatic        | failure timeline; admin retry path                         |
| `REQUIREMENTS_REVIEW_REQUIRED` | `AWAITING_DOCUMENTS`              | requirements review approved    | operator     | manual           | reviewer stored, upload enabled                            |
| `AWAITING_DOCUMENTS`           | `DOCUMENTS_PARTIAL`               | partial upload complete         | API/worker   | automatic        | missing document webhook                                   |
| `AWAITING_DOCUMENTS`           | `DOCUMENTS_UPLOADED`              | all required types present      | API/worker   | automatic        | analysis jobs queued                                       |
| `DOCUMENTS_PARTIAL`            | `DOCUMENTS_UPLOADED`              | remaining documents uploaded    | API/worker   | automatic        | analysis jobs queued                                       |
| `DOCUMENTS_UPLOADED`           | `PROCESSING`                      | analysis job started            | worker       | automatic        | document lock, timeline                                    |
| `PROCESSING`                   | `PROCESSING_FAILED`               | document analysis final failure | worker       | automatic        | blocks Decision Engine                                     |
| `PROCESSING`                   | `ACTION_REQUIRED`                 | Decision Pack recommends action | worker/n8n   | automatic        | Decision Pack, webhook, manual approval disabled           |
| `PROCESSING`                   | `READY_FOR_MANUAL_REVIEW`         | Decision Pack recommends review | worker/n8n   | automatic        | Decision Pack, webhook, manual approval enabled            |
| `ACTION_REQUIRED`              | `DOCUMENTS_PARTIAL`               | additional upload requested     | reviewer/API | manual/automatic | upload reopened                                            |
| `ACTION_REQUIRED`              | `PROCESSING`                      | admin retry                     | admin        | manual           | retry trace                                                |
| `READY_FOR_MANUAL_REVIEW`      | `MANUAL_REVIEW_APPROVED`          | manual review approved          | reviewer     | manual           | `ManualReviewService` only, webhook                        |
| `READY_FOR_MANUAL_REVIEW`      | `MANUAL_REVIEW_REJECTED`          | manual review rejected          | reviewer     | manual           | `ManualReviewService` only, webhook                        |
| `READY_FOR_MANUAL_REVIEW`      | `MANUAL_REVIEW_CHANGES_REQUESTED` | changes requested               | reviewer     | manual           | `ManualReviewService` only, webhook                        |
| `ACTION_REQUIRED`              | `MANUAL_REVIEW_CHANGES_REQUESTED` | changes requested               | reviewer     | manual           | `ManualReviewService` only                                 |

No transition can approve, reject, or request changes without `ManualReviewService`.

## API contract

Minimum endpoints:

| Endpoint                                              | Auth         | Idempotency | Purpose                                                      |
| ----------------------------------------------------- | ------------ | ----------: | ------------------------------------------------------------ |
| `POST /v1/operations`                                 | partner HMAC |         yes | Create operation and enqueue requirements.                   |
| `POST /v1/operations/:operationId/upload-link`        | partner HMAC |         yes | Register document and return presigned upload URL.           |
| `POST /v1/operations/:operationId/documents/complete` | partner HMAC |         yes | Verify uploaded object and enqueue document analysis.        |
| `GET /v1/operations/:operationId/status`              | partner HMAC |          no | Read operation status.                                       |
| `GET /v1/operations/:operationId/analysis`            | partner HMAC |          no | Read operation, latest Decision Pack, and document analyses. |
| `GET /v1/app/operations/:operationId/decision-pack`   | app JWT      |          no | Read latest Decision Pack for dashboard review.              |
| `POST /v1/app/operations/:operationId/manual-review`  | app JWT      |         yes | Final human review action.                                   |
| `POST /v1/webhooks/test`                              | partner HMAC |         yes | Test signed webhook delivery by `webhookId` body.            |

Existing endpoints remain supported for compatibility: `/upload-sessions`, `/documents`, `/analysis-results`, `/document-requirements`, and `/webhooks/:webhookId/test`.

Partner auth uses `X-PayFi-Api-Key`, `X-PayFi-Nonce`, and `X-PayFi-Signature`. Mutating partner endpoints use `Idempotency-Key`. Tenant isolation derives `organizationId` and `partnerIntegrationId` from auth, never from the public body.

## Decision Pack

`operation_decision_packs` is the operation-level audit contract.

Representative fields (the published JSON Schema is authoritative for the complete required set):

```json theme={null}
{
  "decisionPackId": "dp_example",
  "schemaVersion": 2,
  "operationId": "op_example",
  "analysisRunId": "job_example",
  "status": "DECISION_PACK_READY",
  "analysisOutcome": "SUCCEEDED",
  "qualityStatus": "VALID",
  "analysisMode": "DETERMINISTIC_RULES",
  "fallbackUsed": false,
  "sourceCoverage": "COMPLETE",
  "inputSnapshotHash": "b49177e05868b7af5284dfeac8c8032a6080d7cf5c98c4f614046cf887035d9a",
  "analysisDisposition": "VALID",
  "provenance": {
    "analysisContractVersion": "2",
    "workflow": {
      "id": "Rsmrc2p5STzykAWj",
      "activeVersionId": "version_example",
      "contentHash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    },
    "model": {
      "provider": "deterministic",
      "name": "decision-rules",
      "profile": "decision-rules-v2"
    },
    "promptVersion": "document-analysis-v2",
    "rulesVersion": "payfi-rules-0.4.0",
    "partnerPolicy": {
      "id": "policy_example",
      "version": "approved-policy-v1",
      "sourceHash": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
    },
    "regulatoryCorpus": {
      "version": "br-cambio-2026-07-21.1",
      "manifestHash": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
    },
    "ocr": {
      "serviceVersion": "0.3.0",
      "engine": "pymupdf+tesseract"
    },
    "regdocs": {
      "serviceVersion": "1.1.0"
    }
  },
  "versionMetadata": {
    "workflowVersion": "version_example",
    "modelVersion": "decision-rules",
    "promptVersion": "document-analysis-v2",
    "policyVersion": "approved-policy-v1",
    "rulesVersion": "payfi-rules-0.4.0",
    "regulatoryCorpusVersion": "br-cambio-2026-07-21.1"
  },
  "regulatoryCorpusVersion": "br-cambio-2026-07-21.1",
  "policyVersion": "approved-policy-v1",
  "rulesVersion": "payfi-rules-0.4.0",
  "modelProfile": "decision-rules-v2",
  "overallScore": 8.2,
  "score0To100": 82,
  "riskLevel": "LOW",
  "recommendedStatus": "READY_FOR_MANUAL_REVIEW",
  "reviewPosture": "STANDARD_REVIEW",
  "blockingReasons": [],
  "warnings": ["MANUAL_REVIEW_REQUIRED"],
  "citations": []
}
```

The full persisted schema also includes operation facts, document coverage, entity reconciliation, nature decision, regulatory checks, policy checks, fraud signals, score breakdown, reason codes, source evidence, action items, redacted processing trace events, version metadata, and created timestamp. It does not persist prompt text, model raw output, document binaries, credentials, or PII-bearing traces.

## Deterministic score

Score is calculated by deterministic rules over validated evidence. Each factor records its reason code, severity, source, and impact. If the required evidence is incomplete or a critical source is unavailable, the engine abstains and leaves score fields unset instead of fabricating a number.

| Reason                               | Penalty |
| ------------------------------------ | ------: |
| Critical required document missing   |  `-4.0` |
| Medium required document missing     |  `-2.0` |
| Amount mismatch                      |  `-3.0` |
| Currency mismatch                    |  `-3.0` |
| Bank account mismatch                |  `-4.0` |
| Invalid CPF/CNPJ                     |  `-3.0` |
| Nature mismatch                      |  `-2.0` |
| Low OCR confidence in critical field |  `-1.5` |
| Duplicate invoice/hash               |  `-5.0` |
| Suspicious PDF metadata              |  `-2.0` |

Status rules:

* Any critical flag yields `ACTION_REQUIRED`.
* Missing critical required document yields `ACTION_REQUIRED`.
* Score `>= 8` with no critical flag, complete sources, valid quality, and no fallback yields `READY_FOR_MANUAL_REVIEW`.
* Score `>= 6` and `< 8` yields `READY_FOR_MANUAL_REVIEW` with `REVIEW_WITH_WARNINGS`.
* Score `< 6` yields `ACTION_REQUIRED`.

The score is operational guidance. It never approves an operation, and the model cannot freely generate the final score or status.

## Reason codes

Core reason codes include:

`MISSING_REQUIRED_DOCUMENT`, `MISSING_CRITICAL_DOCUMENT`, `BANK_ACCOUNT_MISMATCH`, `BUYER_OWNER_MISMATCH`, `DOCUMENT_REFERENCE_MISMATCH`, `AMOUNT_MISMATCH`, `CURRENCY_MISMATCH`, `INVALID_TAX_ID`, `INVALID_SWIFT_BIC`, `INVALID_IBAN`, `NATURE_MISMATCH`, `LOW_OCR_CONFIDENCE`, `DUPLICATE_DOCUMENT_HASH`, `SUSPICIOUS_PDF_METADATA`, `NO_REGULATORY_SOURCE_FOUND`, `POLICY_RULE_TRIGGERED`, `POLICY_NOT_CONFIGURED`, `MALWARE_DETECTED`, `DOCUMENT_ANALYSIS_FAILED`, `UNTRUSTED_ANALYSIS_RESULT`, `SCHEMA_VALIDATION_FAILED`, `STALE_DECISION_PACK`, `MANUAL_REVIEW_REQUIRED`, `DOCUMENTS_VALIDATED`, `NATURE_CONFIRMED`, `HUMAN_OVERRIDE_APPLIED`.

Critical and high evidence problems are blocking by default. `NO_REGULATORY_SOURCE_FOUND`, `POLICY_NOT_CONFIGURED`, schema failure, degraded execution, or stale input blocks a ready result and requires remediation or review. A permitted human override remains a separate audit record; the original signal and impact stay in history.

## Human review

Manual review accepts `APPROVE`, `REJECT`, `REQUEST_CHANGES` and the legacy lowercase equivalents.

Payload:

```json theme={null}
{
  "decisionPackId": "dp_example",
  "decision": "APPROVE",
  "reasonCodes": ["DOCUMENTS_VALIDATED", "NATURE_CONFIRMED"],
  "overrideReasonCode": "DOCUMENTARY_EVIDENCE_REVIEWED",
  "overrideJustification": "Evidências reconciliadas e conferidas pelo analista.",
  "comment": "Aprovado após revisão da invoice e contrato.",
  "overrides": {
    "nature": {
      "from": "46057",
      "to": "47575",
      "reason": "Evidência documental confirma licenciamento de software."
    }
  },
  "requestedDocuments": []
}
```

The server persists reviewer ID, timestamp, latest Decision Pack ID when available, reason codes, comments, overrides, requested documents, previous status by audit trail, next status, and webhook delivery.

Approval is accepted only against the latest current, complete, `VALID` Decision Pack with no critical blocker. A valid pack with a low score or contrary recommendation requires an override reason code and justification. `REVIEW_REQUIRED`, `INVALID`, and `DEGRADED` packs only allow rejection or requested changes.

Human review does not mutate historical score. Overrides are audit records and may feed future datasets only after redaction/pseudonymization and legal approval.

## Webhooks

Payloads are redacted and never include raw documents, OCR text, prompts, completions, presigned URLs, secrets, signatures, or full tax IDs.

New fields are additive and backward-compatible:

```json theme={null}
{
  "eventId": "evt_123",
  "eventType": "operation.analysis.completed",
  "event": "operation.analysis.completed",
  "operationId": "op_123",
  "externalOperationId": "BRAZA-123",
  "partnerOperationId": "BRAZA-123",
  "status": "READY_FOR_MANUAL_REVIEW",
  "decisionPackId": "dp_123",
  "decisionSummary": {
    "score": 8.2,
    "riskLevel": "LOW",
    "recommendedStatus": "READY_FOR_MANUAL_REVIEW",
    "blockingReasons": [],
    "actionItemsCount": 0
  },
  "occurredAt": "2026-06-03T15:00:00-03:00"
}
```

Webhook deliveries are HMAC-signed, idempotent by context/event, retried with backoff, and logged with redacted payload and response body hash.

## LGPD retention matrix

| Data type                 | Storage                   |                                                                    Retention | Access                        | Dataset use            |
| ------------------------- | ------------------------- | ---------------------------------------------------------------------------: | ----------------------------- | ---------------------- |
| Raw document              | Brazil object storage     | immediate after success/terminal failure; 24 hours max during eligible retry | system/admin restricted       | no                     |
| Raw OCR                   | not persisted             |                                                                         none | n/a                           | no                     |
| Extracted fields          | Postgres                  |                                                          audit contract term | reviewer/admin scoped         | after pseudonymization |
| SHA-256 hash              | Postgres                  |                                                              long-term audit | system/admin                  | yes                    |
| Technical metadata        | Postgres                  |                                                              long-term audit | admin/reviewer limited        | yes                    |
| Redacted Decision Pack    | Postgres                  |                                                              long-term audit | partner/reviewer/admin scoped | after review           |
| Full prompt               | not persisted             |                                                                         none | n/a                           | no                     |
| Raw LLM response with PII | not persisted by default  |                                                  none or short encrypted TTL | admin only                    | no                     |
| Webhook payload           | Postgres                  |                                                          delivery audit term | admin scoped                  | no                     |
| Admin raw timeline        | Postgres encrypted fields |                                                                   audit term | admin only                    | no                     |
| Fine-tuning dataset       | separate approved dataset |                                                               legal approval | restricted                    | yes, redacted only     |

## Regulatory obligations and active policy

Regulatory obligations follow:

```text theme={null}
draft -> review_pending -> approved -> active -> superseded -> archived
```

Active internal policies follow:

```text theme={null}
uploaded -> parsed -> draft -> review_pending -> approved -> active -> superseded -> archived
```

No obligation or client policy can produce an autonomous ready result before
human approval. Requirements resolve from an explicit `policySet` and
`natureCode`. If the client policy is missing, PayFi applies the immutable
versioned default policy, sets `fallbackUsed=true`, uses
`HUMAN_REVIEW_REQUIRED`, and keeps the operation processable. The default is
`system-default-document-policy` v`1` with SHA-256
`97ff1b55faa3209c1908cdb5b08c55f26f26236b58182fc481e01d6c32fe40c8`.
Invalid custom policy data falls back only in `INTERNAL_SUPERVISED_ONLY`; in
authorized evaluation it is fail-closed as `PARTNER_POLICY_NOT_CONFIGURED`,
with `DOCUMENT_REQUIREMENT_POLICY_NOT_CONFIGURED` retained as its legacy alias.

## Scope controls

* C212 is an auditable draft only; no STA submission.
* Sanctions/PEP activates only with partner-provided source/list/policy and approval.
* Legal fine-tuning remains out of MVP.
* Future fine-tuning requires pseudonymized/anonymous data and legal approval.
* Model selection is explicit and versioned. A model, OCR, policy, schema, workflow, or regulatory-source failure is fail-closed and cannot fall back to a ready result.

Decision needed:

* owner: Product + Compliance PayFi
* deadline: before Braza/B\&T pilot with virtual asset operations
* options: `C212_DRAFT_ENABLED` or `C212_DRAFT_DISABLED`
* recommended default: `C212_DRAFT_DISABLED`
* impact if unresolved: C212 can inflate MVP scope and delay the core analysis pilot

## MVP Ready Checklist

* [ ] Migrations applied in the API database.
* [ ] Railway workflow `Rsmrc2p5STzykAWj` active and smoke-tested.
* [ ] `N8N_OPERATION_DECISION_URL` points to `/webhook/operation-decision-engine` in the deployed API environment.
* [ ] Operation happy path reaches `READY_FOR_MANUAL_REVIEW` with a persisted Decision Pack.
* [ ] Missing critical document reaches `ACTION_REQUIRED`.
* [ ] Manual approval/rejection only works via `ManualReviewService`.
* [ ] Webhooks include redacted `decisionPackId` and `decisionSummary`.
* [ ] Dashboard shows Decision Pack before manual review.
* [ ] Schema-invalid n8n output does not persist operation analysis.
* [ ] Policy/corpus versions appear in every Decision Pack.
* [ ] Public logs and webhooks contain no raw document, OCR text, prompt, or PII.
