Implements step 6 from the architecture gap-analysis — a SWIFT gateway module covering the issuance and payment legs plus the ingest path for bank confirmations. Also fixes the pacs.008 → pacs.009 mis-routing flagged by the gap-analysis for the interbank leg. Stacks on PR D.
What lands (all under src/services/swift/)
Outbound generators
module
format
purpose
mt760.ts
FIN Cat-7
SBLC issuance from InstrumentTerms (12 tags, URDG 758 / UCP 600 aware). messageHash() is deterministic so the on-chain plan anchor can be reproduced from the terms.
pacs009.ts
ISO 20022 XML (pacs.009.001.08)
FI-to-FI credit transfer — the interbank leg. BIC-validated on all four agents.
mt202.ts
FIN
FIN equivalent of pacs.009 for non-migrated corridors. Amounts formatted with SWIFT decimal comma.
Inbound parsers
camt.ts#parseCamt025 — Receipt / status of a prior instruction.
camt.ts#reconcileCamt054 — diffs (amount, currency, creditDebitIndicator, endToEndId) and returns the exact mismatches so VALIDATING can feed them into Data.valueMismatch() from PR B.
camt.ts#parseCamt — dispatcher on xmlns marker.
Channel policy (arch §9.2 — accepted ≠ settled)
Documented in swift/index.ts:
pacs.008 stays on the customer-initiated PSP channel (services/iso20022.ts). Acceptance alone does not allow COMMIT.
pacs.009 / MT202 is the interbank channel. COMMIT requires either camt.025 ACSCorcamt.054 CRDT evidence.
Tests
tests/unit/swift.test.ts — 14 cases: MT760 tag layout, MT760 rejects malformed date + negative amount, messageHash determinism, pacs.009 XML + BIC validation + pay-step requirement, MT202 tag layout, camt.025 + camt.054 happy path, xmlns dispatcher, unknown-xmlns rejection, reconcileCamt054 both match-and-mismatch cases.
No network client. These are pure generators + parsers. The actual FIN submission path (SWIFT Alliance Gateway / SAA / SIA) and inbound ingestion (AMH inbox) are operational integrations that belong to the bank's SWIFT service bureau, not the orchestrator.
ExecutionCoordinator wiring is deferred. The issueInstrument step in PR A still executes a mocked dispatch; wiring it to generateMt760(terms) + eventBus.publish('instrument.dispatched', …) is a one-file change that lands in the next coordinator-focused PR so this PR stays reviewable.
Series order
A → B → C → D → E → F → G → H.
Base: devin/1776875718-event-bus-sse (PR D). The diff here is E-only.
Implements **step 6** from the architecture gap-analysis — a SWIFT gateway module covering the issuance and payment legs plus the ingest path for bank confirmations. Also fixes the **pacs.008 → pacs.009** mis-routing flagged by the gap-analysis for the interbank leg. Stacks on PR D.
## What lands (all under `src/services/swift/`)
### Outbound generators
| module | format | purpose |
| --- | --- | --- |
| `mt760.ts` | FIN Cat-7 | SBLC issuance from `InstrumentTerms` (12 tags, URDG 758 / UCP 600 aware). `messageHash()` is deterministic so the on-chain plan anchor can be reproduced from the terms. |
| `pacs009.ts` | ISO 20022 XML (`pacs.009.001.08`) | FI-to-FI credit transfer — **the interbank leg**. BIC-validated on all four agents. |
| `mt202.ts` | FIN | FIN equivalent of pacs.009 for non-migrated corridors. Amounts formatted with SWIFT decimal comma. |
### Inbound parsers
- `camt.ts#parseCamt025` — Receipt / status of a prior instruction.
- `camt.ts#parseCamt054` — Bank-to-customer credit/debit notification.
- `camt.ts#reconcileCamt054` — diffs `(amount, currency, creditDebitIndicator, endToEndId)` and returns the exact mismatches so `VALIDATING` can feed them into `Data.valueMismatch()` from PR B.
- `camt.ts#parseCamt` — dispatcher on xmlns marker.
### Channel policy (arch §9.2 — accepted ≠ settled)
Documented in `swift/index.ts`:
- `pacs.008` stays on the customer-initiated PSP channel (`services/iso20022.ts`). Acceptance alone does **not** allow COMMIT.
- `pacs.009` / `MT202` is the interbank channel. COMMIT requires either `camt.025 ACSC` **or** `camt.054 CRDT` evidence.
## Tests
`tests/unit/swift.test.ts` — 14 cases: MT760 tag layout, MT760 rejects malformed date + negative amount, `messageHash` determinism, pacs.009 XML + BIC validation + pay-step requirement, MT202 tag layout, camt.025 + camt.054 happy path, xmlns dispatcher, unknown-xmlns rejection, `reconcileCamt054` both match-and-mismatch cases.
## Verification
```
$ npx tsc --noEmit # clean
$ npx jest # 74 passed, 6 suites
```
## Not in this PR
- **No network client.** These are pure generators + parsers. The actual FIN submission path (SWIFT Alliance Gateway / SAA / SIA) and inbound ingestion (AMH inbox) are operational integrations that belong to the bank's SWIFT service bureau, not the orchestrator.
- **ExecutionCoordinator wiring is deferred.** The `issueInstrument` step in PR A still executes a mocked dispatch; wiring it to `generateMt760(terms)` + `eventBus.publish('instrument.dispatched', …)` is a one-file change that lands in the next coordinator-focused PR so this PR stays reviewable.
## Series order
A → B → C → D → **E** → F → G → H.
Base: `devin/1776875718-event-bus-sse` (PR D). The diff here is E-only.
nsatoshi
changed target branch from devin/1776875718-event-bus-sse to main2026-04-22 10:16:28 -07:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Implements step 6 from the architecture gap-analysis — a SWIFT gateway module covering the issuance and payment legs plus the ingest path for bank confirmations. Also fixes the pacs.008 → pacs.009 mis-routing flagged by the gap-analysis for the interbank leg. Stacks on PR D.
What lands (all under
src/services/swift/)Outbound generators
mt760.tsInstrumentTerms(12 tags, URDG 758 / UCP 600 aware).messageHash()is deterministic so the on-chain plan anchor can be reproduced from the terms.pacs009.tspacs.009.001.08)mt202.tsInbound parsers
camt.ts#parseCamt025— Receipt / status of a prior instruction.camt.ts#parseCamt054— Bank-to-customer credit/debit notification.camt.ts#reconcileCamt054— diffs(amount, currency, creditDebitIndicator, endToEndId)and returns the exact mismatches soVALIDATINGcan feed them intoData.valueMismatch()from PR B.camt.ts#parseCamt— dispatcher on xmlns marker.Channel policy (arch §9.2 — accepted ≠ settled)
Documented in
swift/index.ts:pacs.008stays on the customer-initiated PSP channel (services/iso20022.ts). Acceptance alone does not allow COMMIT.pacs.009/MT202is the interbank channel. COMMIT requires eithercamt.025 ACSCorcamt.054 CRDTevidence.Tests
tests/unit/swift.test.ts— 14 cases: MT760 tag layout, MT760 rejects malformed date + negative amount,messageHashdeterminism, pacs.009 XML + BIC validation + pay-step requirement, MT202 tag layout, camt.025 + camt.054 happy path, xmlns dispatcher, unknown-xmlns rejection,reconcileCamt054both match-and-mismatch cases.Verification
Not in this PR
issueInstrumentstep in PR A still executes a mocked dispatch; wiring it togenerateMt760(terms)+eventBus.publish('instrument.dispatched', …)is a one-file change that lands in the next coordinator-focused PR so this PR stays reviewable.Series order
A → B → C → D → E → F → G → H.
Base:
devin/1776875718-event-bus-sse(PR D). The diff here is E-only.8dcdb4531cto632f309ffc