Skip to content

Add Bank-to-VASP Control Room demo and reference-stack updates - #1

Open
Raafet57 wants to merge 43 commits into
tomalaerts-dev:mainfrom
Raafet57:main
Open

Add Bank-to-VASP Control Room demo and reference-stack updates#1
Raafet57 wants to merge 43 commits into
tomalaerts-dev:mainfrom
Raafet57:main

Conversation

@Raafet57

@Raafet57 Raafet57 commented Apr 23, 2026

Copy link
Copy Markdown

Hi @tomalaerts-dev / Tom,

I’d value your review on the latest pacs.crypto reference-stack and reviewer-demo developments from my fork.

What changed

Reference stack / execution wedge

  • Adds an executable Node reference server for the Bank-to-VASP flow.
  • Adds routes and tests for Travel Rule submission/callback, instruction quote/submission/status, finality, webhooks, exceptions, returns/reversals, and reporting surfaces.
  • Adds a mock chain adapter path plus guarded Sepolia USDC adapter tooling.
  • Adds conformance, roadmap, backlog, architecture, chain-adapter, webhook, exception-family, and interop documentation.

Reviewer-facing demo surfaces

  • Adds a standalone bank-to-vasp-control-room.html Control Room demo shell.
  • Adds real happy-path payload samples and identifiers under docs/demo-samples/happy-path/.
  • Updates README.md, docs/demo-bank-to-vasp.md, and index.html navigation so reviewers can find the demo.
  • Adds QA packets for the Control Room smoke/remediation/final reconciliation.

Video/demo packet

  • Adds a narrated HyperFrames review packet at:
    • docs/media/control-room-demo-video-2026-07-09/README.md
    • docs/media/control-room-demo-video-2026-07-09/renders/pacs-control-room-demo-720p-review.mp4
  • Includes source files (index.html, SCRIPT.md, DESIGN.md), narration audio, timed UI capture, and contact sheet.

Verification already run

  • reference-server tests: 95 passing, 1 funded-Sepolia integration skipped unless explicitly enabled.
  • Control Room static checks: embedded JSON payloads parse; inline JS parses with node --check.
  • HyperFrames video packet:
    • lint: 0 errors, 0 warnings
    • validate: pass, no console errors
    • inspect: 0 layout issues
    • ffprobe: 106s H.264/AAC review MP4
  • Secret/local-path scan on the latest video packet: 0 hits.

Explicit boundaries

  • Sepolia-funded execution remains gated and is not run by default.
  • The Control Room video/demo is a reviewer artifact, not a production or certification claim.
  • No deploy, hosted publication, or production operation is included in this PR.

Thanks,
Raf

@Raafet57

Copy link
Copy Markdown
Author

Small clarification: this is review-only for now, not a merge request. I opened it as a draft to get your thoughts on the direction, architecture, and message-family boundaries before considering whether any of it should be merged.

@tomalaerts-dev

Copy link
Copy Markdown
Owner

Hi sir. I like the idea of making it executable, that is a great step forward where eI had not yet spent energy on.
A remark, a number of your comments on certain pacs and camt functionality will be in my next update. so I think it is better to let your AI check if some of the questions/ideas are not resolved yet.
You know what, I will already upload everything now (give me a few minutes), will do the LinkedIn tomorrow

@tomalaerts-dev

Copy link
Copy Markdown
Owner

OK done, have a look already. a reporting yaml is added and various refinements everywhere,

@Raafet57

Copy link
Copy Markdown
Author

I`m on it

Raafet57 and others added 13 commits April 23, 2026 20:45
Integrate Tom Alaerts' v1.3 spec-family release while preserving this
fork's reference-server + docs layer.

Brought in from upstream/main (a450dbc..d546a8a):
- unified v1.3 filenames (travel-rule / instruction / account-reporting,
  renamed from the old v3 / v1 / camt-crypto-reporting names)
- Spec 4: Exception & Investigation API + ei-simulator (camt.110/111)
- Spec 5: Liquidity Management API + liquidity-simulator
- optional debtor/creditor agents, SELF_CUSTODY model, rewritten README

Conflicts resolved by keeping both sides:
- README.md: Tom's v1.3 spec narrative + this fork's reference-stack
  "Current Direction" section; all filename references updated to v1.3
- instruction-simulator-v1.3.html: kept the Live-API "Execution Mode"
  block and Tom's new v1.3 returns/reversals fields

travel-rule-simulator-v1.3.html auto-merged cleanly (Live-API additions
and v1.3 tweaks did not overlap). reference-server/ was untouched by
upstream; full suite (48 tests) passes after the merge.
Follow-on to the upstream v1.3 merge: update the conformance matrix,
demo walkthrough, and roadmap to cite Tom's renamed spec files.

- travel-rule-api-v3.yaml        -> travel-rule-api-v1.3.yaml
- instruction-api-v1.yaml        -> instruction-api-v1.3.yaml
- camt-crypto-reporting-v1.yaml  -> account-reporting-api-v1.3.yaml
- *-simulator-v3/v1.html          -> *-simulator-v1.3.html

Reference semantics (camt.052/053/054 mappings) are unchanged; only the
spec filenames moved.
Raafet57 added 14 commits June 16, 2026 10:39
Make the reference server and its docs coherent with the v1.3 specs merged
from upstream, without widening the FULL_CUSTODY / EVM wedge.

Server conformance fixes (real bugs — v1.3-valid requests were rejected):
- accept the new v1.3 `SELF_CUSTODY` custody model at the API surface (no
  longer a 400); the wedge executes FULL_CUSTODY only, so SELF_CUSTODY and
  DELEGATED_SIGNING now return 501 with a clear message
- make debtor_agent / creditor_agent optional on instruction and travel-rule
  submission (v1.3 corporate-direct / self-hosting flows); debtor and creditor
  parties stay mandatory
- add tests for both behaviours — 50 tests pass

Docs coherence:
- conformance.md: agent/custody notes; new rows for the v1.3 instruction
  return / reverse / reversal-status endpoints; Spec 4 (exception-investigation,
  camt.110/111) and Spec 5 (liquidity) status; /exceptions/* extension note
- exception-family.md: how the first-slice /exceptions/* model relates to v1.3
  Spec 4 and the instruction-level returns/reversals (same "never rewrite
  FINAL" rule, different surface)
- roadmap.md + README: record v1.3 alignment status and follow-ups
Add a strategic research note plus an expansion roadmap and backlog,
grounded in a June 2026 survey of the DeFi/TradFi interoperability
landscape and mapped onto pacs.crypto's ISO 20022 bridge.

New:
- docs/interop-defi-tradfi.md - landscape (SWIFT+Chainlink CCIP/CRE,
  ERC-7943/ERC-3643/ISO 24165, Project Guardian Trust Anchors, BIS Agora /
  unified ledger, CCTP/Canton, vLEI/GLEIF, FATF Travel Rule, MiCA/GENIUS,
  x402/AP2/MPP) with cited sources, 10 scored opportunities (O1-O10),
  and guardrails
- docs/interop-roadmap.md - horizon-based (H0-H3) expansion roadmap,
  sequenced strictly behind the current wedge

Updated:
- docs/backlog.md - Epics 15-24 (P3/Deferred), one per opportunity,
  tagged by horizon and cross-referenced to Epic 14
- docs/roadmap.md + README - cross-links to the new interop docs

All directions are post-wedge and additive; nothing changes the current
execution program or the v1.3 conformance follow-ups.
All optional and additive; absent fields are unaffected, existing tests stay green.

- Epic 16 (vLEI): validate optional vlei_credential (credential_id, issuer_lei,
  status) on parties and agents
- Epic 17 (transport): validate optional blockchain_instruction.settlement_transport
  (DIRECT_EVM / CCTP / CCIP / CANTON)
- Epic 20 (RWA): validate optional credential_attestation incl. ERC-7943 / ERC-3643
  enforcement context on instruction + travel-rule submissions
- test/interop-fields.test.js: 5 new tests; 55 tests pass total
…18/19/23)

- Epic 18: mock Circle CCTP V2 settlement adapter composing the mock EVM
  lifecycle and surfacing cross-chain burn-and-mint metadata; selectable via
  REF_SERVER_CHAIN_ADAPTER=mock-cctp. Proves the chain-adapter seam supports a
  second venue with no route change.
- Epic 19: bidirectional pacs.crypto Spec 1 <-> IVMS101 core-field mapping
  (name, LEI, country, wallet) so the Travel Rule model bridges TRISA/TRP;
  unmapped fields reported, not dropped.
- Epic 23: x402 agent-intent -> compliant pacs.crypto instruction binding
  (ISO 24165 DTI-first resolution, SELF_CUSTODY default, Travel Rule gap
  surfaced as a warning).
- 6 new tests (cctp/ivms101/x402); 61 tests pass.
DELEGATED_SIGNING instructions now execute end to end instead of returning 501:

- POST /instruction with DELEGATED_SIGNING is held with an unsigned transaction
  (adapter buildUnsignedTransaction) and awaiting_signed_transaction = true
- the lifecycle is gated at PENDING until the signed transaction arrives
- POST /instruction/{id}/signed-transaction validates and accepts the signed
  transaction (SignedTransactionSubmission), lifts the gate, and resumes the
  normal BROADCAST -> CONFIRMING -> FINAL progression on unchanged route shapes
- SELF_CUSTODY still returns 501; FULL_CUSTODY and DELEGATED_SIGNING execute
- the old "out of scope" test is rewritten into a full delegated flow test plus
  an unknown / non-delegated rejection test; 62 tests pass
…reporting (Epics 21/22)

Messaging-layer modules, anti-tipping-off discipline throughout:

- Epic 21 (trust-anchor): buildAccessCredential / verifyAccessCredential for the
  Project Guardian permissioned-pool model. Asserts ELIGIBLE/NOT_ELIGIBLE and
  carries identity (LEI/vLEI), never sanctions reasoning; verify enforces scope,
  vLEI requirement, and expiry.
- Epic 22 (compliance-reporting): one canonical record -> regime-specific filings
  (MiCA auth.117-shaped + GENIUS-shaped) from a single substrate; DTI-first; no
  sanctions reasoning emitted.
- 5 new tests; 67 tests pass.
…acklog

- backlog.md: Epic 13 -> Implemented; Epics 15-23 -> "Implemented (reference
  slice)"; section intro notes the implementation pass; Epic 24 stays deferred
  (externally gated)
- conformance.md: signed-transaction route now Implemented; custody + interop
  field notes; new "Interoperability reference modules" table (Epics 15-23)
- README: delegated signing and the interop reference layer reflected in the
  reference-stack status
… review

Delegated signing (db.js) — three HIGH correctness bugs:
- a cancelled (or expired) held instruction could be revived by submitting the
  signed transaction: the sign path gated only on awaiting_signed_transaction,
  not status. Now require status==='PENDING' too.
- concurrent signed-transaction submissions both cleared the gate (non-atomic
  check-then-act) -> double progression / lost update. Now serialized per
  instructionId via inFlightSignedTransactions, mirroring createInstruction.
- a held instruction never expired, and resetting created_at to signing time
  corrupted reporting/finality timestamps and could spuriously EXPIRE a
  just-signed instruction. Now created_at (acceptance) is preserved and the
  held gate expires the instruction when its signing window lapses.

Coherence / modules:
- credential_attestation now round-trips through the store (was validated then
  dropped); carried in normalizeInstructionSubmission + the record (Epics 16/20).
- x402 binding: beneficiary wallet placed at top-level creditor_account (was
  nested under blockchain_instruction and dropped); empty-string id resolution
  treated as unresolved.
- trust-anchor verify enforces expiry even when policy.now is omitted; comment
  clarifies eligibility is a vouch, not a screening-result disclosure.
- validators: note that ERC-7943 enforcement booleans are token capabilities,
  not per-counterparty decisions.
- backlog Epic 23 acceptance reworded (Travel Rule surfaced as a warning).

7 regression tests added (cancel-then-sign, concurrent sign, held expiry,
invalid format, attestation round-trip, x402 wallet placement, trust-anchor
expiry); 74 tests pass.
…ffold

- Epics 19/21/22/23: wire the interop reference modules into stateless
  /interop/* HTTP routes (travel-rule<->ivms101, access-credentials [+verify],
  compliance-filings, x402/bind) so the directions are reachable over the wire,
  not just importable
- Epic 24: add a reference scaffold (unified-ledger pre-settlement posture, BIS
  Agora model) + /interop/unified-ledger/pre-settlement route, clearly marked as
  a scaffold gated on external maturity (not a production commitment)
- conformance.md / backlog.md updated; 6 new route tests; 80 tests pass
…d integration test

Epics 10/11: the "real instruction produces a real on-chain tx hash reaching
FINAL" acceptance is now an executable test (test/sepolia-funded.integration.test.js)
rather than a manual ritual. It runs a real Sepolia USDC broadcast and asserts a
real 0x tx hash, but only when the operator opts in
(REF_SERVER_SEPOLIA_FUNDED_TEST=1) with funded REF_SERVER_SEPOLIA_* credentials;
otherwise it skips with an explanatory reason. The surrounding
safety/corridor/lifecycle behaviour is already covered by stub-based tests.

81 tests: 80 pass, 1 gated-skip. backlog updated.
The review caught three real regressions in the delegated-signing fixes:

- lifecycle was anchored to created_at (acceptance), so a realistically-delayed
  signature jumped straight to FINAL skipping BROADCAST/CONFIRMING with a block
  timestamp BEFORE the signature. Added lifecycle_anchor_at (set at signing);
  the mock adapter derives elapsed time + executed-state timestamps from it
  while created_at stays at acceptance for reporting/history.
- delegated signing never broadcast on a real adapter: the resume path only
  called deriveLifecycleState, but a real adapter broadcasts in
  submitLifecycleState. The sign path now invokes submitLifecycleState on resume
  (mock falls back to the simulated clock).
- a cancelled held instruction flipped CANCELLED -> EXPIRED after its expiry:
  cancel now clears awaiting_signed_transaction/unsigned_transaction, and the
  held-gate guards on status === 'PENDING' so a terminal record is never
  re-expired.

Low-severity edge fixes: x402 amount 0 no longer warns "missing"; trust-anchor
verify falls back to current time when policy.now is unparseable; IVMS101 omits
empty person / null-name records.

6 regression tests; 86 tests (85 pass, 1 gated Sepolia skip).
…ng redesign)

The re-run review found my round-2 "broadcast on resume" fix was wrong on a real
adapter, plus a residual anchor bug and edge cases:

- HIGH: on the custodial Sepolia adapter, the resume path called
  submitLifecycleState, which re-signs and broadcasts with the SERVER's own key,
  ignoring the party's signed transaction (and failing the corridor check).
  Delegated signing is now an explicit adapter capability (supports_delegated_
  signing): the mock simulates it; a custodial adapter rejects DELEGATED_SIGNING
  with 501 at submission. The custodial submitLifecycleState path is no longer
  used on resume; the mock resumes on the simulated clock.
- MEDIUM: the mock's buildUnsignedTransaction leaked onto every adapter via the
  normalizeChainAdapter spread, so a non-supporting adapter handed a delegated
  client a fabricated unsigned tx. Held-state + unsigned_transaction are now
  gated on the capability; the dead {transaction_format:'OTHER'} fallback removed.
- HIGH: a delegated instruction signed near its expiry could flip to EXPIRED
  because deriveLifecycleState still checked the original expiry while the
  lifecycle was anchored at sign time. Signing now clears expiry_date_time.
- MEDIUM: /execution-status now surfaces awaiting_signed_transaction so a held
  payment is distinguishable from a queued one.
- LOW: trust-anchor fails closed on a malformed expiry and uses a strict-boolean
  screening flag; x402 maps a null amount to undefined (not 'null'); IVMS101
  keeps a party that has LEI/country but no name.

Tests: replaced the (wrong-behaviour) broadcast-on-resume test with a rejection
test, added a post-sign near-expiry regression. 87 tests (86 pass, 1 gated).
…ce, adapter fail-open)

- MEDIUM: TOCTOU race between sign and cancel on a held delegated instruction.
  The sign lock did not cover cancelInstructionAsync, so a concurrent cancel+sign
  could clobber or revive each other. All mutating ops on one instruction (sign
  AND cancel) now serialize through a single per-instruction lock
  (runWithInstructionLock); the sign-only inFlightSignedTransactions map is gone.
- MEDIUM: adapter fail-open. A custom adapter omitting supports_delegated_signing
  inherited the mock fallback's `true` via the normalizeChainAdapter spread.
  Normalization is now fail-closed (an adapter must explicitly opt in); a null
  adapter returns the mock directly; mock-cctp states the flag explicitly.
- LOW: compliance-filings maps a JSON-null `regimes` to the default set instead
  of throwing; IVMS101 omits empty debtor/creditor parties.

Rewrote the concurrent-sign test for the serialized semantics and added a
sign/cancel race regression. 88 tests (87 pass, 1 gated).
…402/IVMS edges)

- MEDIUM: releaseExpiredHold ran from unlocked read paths (GET / search / the
  create-time duplicate check), so concurrent reads of an expired held
  instruction could double-emit the EXPIRED outbox event. Added a synchronous
  compare-and-swap re-read so the transition + emit happen exactly once.
- LOW: x402 resolve() now looks up own properties only (so keys like
  'constructor'/'toString' no longer resolve to inherited prototype members) and
  omits an undefined debtor name instead of carrying name:undefined.
- LOW: IVMS101 mapping reports dropped vLEI credentials and non-country address
  subfields in `unmapped` per its "never silently drop" contract.

Note: the broader read-advances-lifecycle concurrency (concurrent unlocked reads
can double-emit an outbox event for ANY transition, not just delegated) is a
pre-existing engine property, not introduced here; engine-wide idempotency is a
separate scoped follow-up. 88 tests (87 pass, 1 gated).
Raafet57 added 3 commits July 7, 2026 20:49
# Conflicts:
#	docs/conformance.md
#	reference-server/src/routes/instruction-routes.js
Add the standalone reviewer Control Room shell, local demo navigation, and QA reconciliation packets for the Bank-to-VASP happy-path walkthrough.
@Raafet57 Raafet57 changed the title Turn pacs.crypto into an executable bank-to-VASP reference stack Add Bank-to-VASP Control Room demo and reference-stack updates Jul 9, 2026
@Raafet57
Raafet57 marked this pull request as ready for review July 9, 2026 12:01
@Raafet57

Raafet57 commented Jul 9, 2026

Copy link
Copy Markdown
Author

@tomalaerts-dev quick update: this PR now includes the latest Control Room shell, QA packets, and the narrated HyperFrames review video packet. Head is f9c4b15e3cf9dd30f6daf52eae38ef7e2033e87c from Raafet57/main.

Key review entry points:

  • bank-to-vasp-control-room.html
  • docs/demo-bank-to-vasp.md
  • docs/qa/control-room-final-packet-2026-07-08.md
  • docs/media/control-room-demo-video-2026-07-09/README.md
  • docs/media/control-room-demo-video-2026-07-09/renders/pacs-control-room-demo-720p-review.mp4

Boundary: this remains a reviewer/demo artifact; no production deploy or funded Sepolia run is implied.

@Raafet57

Copy link
Copy Markdown
Author

@tomalaerts-dev, one follow-up after comparing your current main with my fork.

All five root v1.3 OpenAPI YAMLs in my fork remain unchanged from your canonical versions. My delta is therefore mainly the executable reference stack, conformance work, Control Room, QA evidence, and the narrated review video already linked above.

Your README names the Compliance Base Info Reporting API as the next planned family specification. My fork contains a small non-normative seed for that direction: one canonical transaction/compliance record can emit a representative MiCA auth.117-shaped projection and a second regime-shaped projection, with tests. It is only a prototype, not a regulator-ready mapping: it does not yet cover auth.116/auth.118, persistence, retention, version chains, lifecycle timestamps, or official schema validation.

Rather than add more scope to this broad PR, would a separate narrow design note be useful? I could propose:

  1. the canonical base-record boundary and lifecycle;
  2. corrected-record/version-chain semantics;
  3. a projection endpoint that prepares mapping-ready output but does not submit regulatory filings;
  4. a field-by-field auth.116/auth.117/auth.118 mapping annex;
  5. fixtures derived from the running bank-to-VASP flow;
  6. explicit anti-tipping-off and non-compliance-claim boundaries.

I would keep it as an unversioned draft until you choose the name and family release, and only turn it into a focused OpenAPI PR after your design feedback.

Best,
Raf

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants