Skip to content

feat(fdc3): post-trade cash-leg payment transfer — StartPayment → pacs.008/pacs.002 reference receiver (Spec 016) - #470

Open
Synaptics-Lab wants to merge 57 commits into
finos:mainfrom
Synaptics-Lab:feature/016-post-trade-settlement-bankerx
Open

Synaptics-Lab wants to merge 57 commits into
finos:mainfrom
Synaptics-Lab:feature/016-post-trade-settlement-bankerx

Conversation

@Synaptics-Lab

@Synaptics-Lab Synaptics-Lab commented Sep 24, 2026 •

Copy link
Copy Markdown

PR Description

Scope correction (2026-10-12, per maintainer review). This PR's title and summary originally described the work as "BankerX DvP settlement". A DvP reading is wrong for this state: no security leg is ever delivered, and no simultaneous second-currency leg is exchanged. The state demonstrates a currency payment transfer — the cash leg of an already-executed trade (see specs/016-post-trade-settlement-bankerx/spec.md §0, "Terminology — what this state actually demonstrates"). Title and description are aligned to that scope here; the underlying behavior is unchanged.

1. Summary of Changes

This pull request introduces Spec 016: Post-Trade Cash-Leg Payment Transfer (TraderX ↔ BankerX) to TraderX, completing the trading lifecycle from pricing (Spec 008) and order matching (Spec 009) through to post-trade cash settlement.

When a trade executes in the TraderX blotter, the trader raises the FINOS FDC3 3.0 intent fdc3.raiseIntent("StartPayment", paymentContext); the settled currency amount owed on the trade is dispatched to the counterparty over the settlement rail. The UETR (RFC 4122 UUIDv4) keys the payment back to the original trade; the blotter row's status reflects that the trade's cash obligation settled. It does not demonstrate securities delivery-versus-payment or payment-versus-payment.

2. What Was Added

  1. Spec 016 artifacts (specs/016-post-trade-settlement-bankerx/):
    • spec.md: FR/NFRs, the two-tier adapter pattern, and an evidence classification section (§0b) distinguishing what each status channel actually proves (on-chain ledger read-back vs. demo-adapter persistence vs. counterparty broadcast).
    • spec.md §0 Terminology: explicit cash-leg scoping (cash leg only; DvP security leg and PvP out of scope).
  2. TraderX FDC3 interoperability upgrade (frontend-overrides, applied over the generated 014 baseline):
    • raiseStartPayment(paymentContext) in fdc3-interop.service.ts dispatching the standardized fdc3.payment intent context (per FINOS PR #2204).
    • RFC 4122 UUIDv4 SWIFT UETR minted per dispatch; debtor/creditor bound from the blotter.
    • Settlement-registry client (position.service.ts GET/POST to /trade-service/trade/trades/settlements/) with guarded adoption: registry entries adopt onto rows by exact UETR or complete trade fingerprint, so an entry can never stamp SETTLED onto an unrelated row.
  3. Trade blotter action column: SETTLE (BANKERX) affordance on confirmed rows; duplicate-dispatch guard (a UETR in flight cannot be re-fired); timeout sweep converts a stalled dispatch into an honest RJCT with a reason and releases the guard for re-raise.
  4. Reference receiver + negative-path hardening:
    • A provider-neutral lifecycle module (payment-lifecycle.mjs) with validatePaymentContext (ISO 4217 currency admission, coupled optional pair/rate frame for FX legs, complete debtor/creditor, networkRouting) and a PaymentReceiver that serializes concurrent same-UETR receives (the settlement rail runs exactly once; losers replay the first outcome marked duplicate), catches thrown rails as honest Pndg (rail error: …, never a fake Acsc), and never rejects receive().
    • A raised-but-rejected agent intent is treated as a dispatch OUTCOME: the row records RJCT honestly and legacy channels are NOT re-fired with the same UETR (double-dispatch risk held closed).
  5. Evidence honesty: the receipt modal now classifies each settlement — a txSignature from the ledger-read-back path shows the on-chain verification; a broadcast-only Acsc is explicitly labeled counterparty Acsc — no tx evidence (mock/demo boundary). No claim is presented as on-chain proof when it is not.
  6. Standard purity & zero vendor lock-in:
    • No blockchain SDKs or proprietary libraries are added to TraderX's shared Angular app.
    • The shared templates/ tree is verified upstream-pristine by a committed purity test (tests/smoke/generated-tree-purity.test.mjs): the 014 composition of upstream templates carries no settlement vocabulary, and all settlement surface lives in the 016 state pack.

3. Verification & Reproduction

  • Offline acceptance flow (no cluster): ./scripts/start-state-016-post-trade-settlement-bankerx-generated.sh --static --serve — blotter + mock receiver on one origin, app directory served from the pack (--dry-run also supported and validated to complete from a clean checkout).
  • Live reference settlement receiver: https://terminal.synapticchain.xyz
  • Test suites (all committed, dependency-free):
    1. payment-instruction.test.mjs — 11 gates (currency mapping, minor-unit rounding, receiver-side validator).
    2. lifecycle-mock-receiver.test.mjs — 14 gates (schema, duplicate replay, honest rejection, concurrent same-UETR, thrown rails, mirror sync).
    3. generated-tree-purity.test.mjs — 4 gates (generation purity proof).
  • Testing steps:
    1. Serve the pack and open the blotter with the ?launcher=1&directory=<appd-url> flow.
    2. Book a spot FX trade and click SETTLE (BANKERX).
    3. Observe the StartPayment resolution log (FR-01604), the receiver receiving fdc3.payment with the UUIDv4 UETR, and the pacs.002-style Acsc status round-trip flipping the originating row (FR-01605/01604/01606).
    4. Re-click the settle action on the same row to see the duplicate-dispatch guard refuse, and the receiver replay the first outcome marked DUPLICATE.

4. Checklist

  • Conforms to the FINOS FDC3 3.0 spec (fdc3.payment per PR #2204).
  • Does not break or regress existing FDC3 intents (ViewOrders, ViewChart, ViewQuote).
  • Preserves local-only fallback when FDC3 agent is unavailable (legacy channels reserved for the no-agent case).
  • Includes dependency-free smoke suites and a commitable generation-purity proof.
  • Scope is the trade's cash leg; DvP securities delivery and PvP are documented out of scope.
  • Contributed under Apache 2.0 license with signed EasyCLA.

…/pacs.002 reference flow (Spec 016)

Signed-off-by: Abdul Shabazz <veritasvaultone@gmail.com>
@netlify

netlify Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for lucky-concha-f3599f ready!

Name Link
🔨 Latest commit 7263f21
🔍 Latest deploy log https://app.netlify.com/projects/lucky-concha-f3599f/deploys/6acd4ee3d2393bddab9f7b61
😎 Deploy Preview https://deploy-preview-470--lucky-concha-f3599f.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@linux-foundation-easycla

linux-foundation-easycla Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

One or more co-authors of this pull request were not found. You must specify co-authors in commit message trailer via:

Co-authored-by: name <email>

Supported Co-authored-by: formats include:

  1. Anything <id+login@users.noreply.github.com> - it will locate your GitHub user by id part.
  2. Anything <login@users.noreply.github.com> - it will locate your GitHub user by login part.
  3. Anything <public-email> - it will locate your GitHub user by public-email part. Note that this email must be made public on Github.
  4. Anything <other-email> - it will locate your GitHub user by other-email part but only if that email was used before for any other CLA as a main commit author.
  5. login <any-valid-email> - it will locate your GitHub user by login part, note that login part must be at least 3 characters long.

Alternatively, if the co-author should not be included, remove the Co-authored-by: line from the commit message.

Please update your commit message(s) by doing git commit --amend and then git push [--force] and then request re-running CLA check via commenting on this pull request:

/easycla

@DovOps

DovOps commented Sep 24, 2026

Copy link
Copy Markdown
Collaborator

Hi @Synaptics-Lab — this looks interesting! Thanks for proposing the post-trade settlement integration.

I checked the failed Docs and Spec Sanity and Spec Kit Root Gates actions. Both fail at the Validate aggregate coverage step because the new specs/016-post-trade-settlement-bankerx/ pack is missing six required artifacts:

  • plan.md
  • tasks.md
  • research.md
  • data-model.md
  • quickstart.md
  • system/architecture.md

Could you add these to complete the state pack and rerun the checks? Both logs report readiness checks passing before stopping at these missing files; later validation may surface additional items once those are in place.

We'd also welcome you on our TraderX call on Friday, September 25, 2026, at 8:00–8:30am ET if you'd like to walk us through the proposal and discuss next steps. We've included an optional slot for this PR in the meeting agenda (#471). Let us know if you'd like to join!

Synaptics-Lab and others added 2 commits September 25, 2026 12:15
…t/architecture for post-trade settlement

Completes the required Spec Kit artifact set for the 016-post-trade-settlement-bankerx
feature: implementation plan, task breakdown, research decisions, data-model deltas,
operator quickstart, and system architecture (trilateral settlement topology).
Unblocks the branch-resolved check-prerequisites gate so CI turns green ahead of the
TraderX Working Group presentation.

Co-Authored-By: Claude Code <noreply@anthropic.com>
- replace raw <8ms/<2ms angle brackets with sub-8ms/sub-2ms (MDX parses them as JSX tags)
- replace $$ math block and \LaTeX with backticks and literal Δ notation (no math plugin configured; braces break MDX JSX)
- verified locally: docusaurus build exit 0, spec coverage gate green

Co-Authored-By: Claude Code <noreply@anthropic.com>
@Synaptics-Lab
Synaptics-Lab force-pushed the feature/016-post-trade-settlement-bankerx branch from 54a9f52 to 1d85569 Compare September 25, 2026 10:54
@Synaptics-Lab

Copy link
Copy Markdown
Author

Hi DovOps — the six Spec Kit artifacts are in (and we found + fixed the next layer your review predicted: MDX compilation — raw <8ms and an unconfigured $$ math block; docusaurus build is green locally). The latest head has EasyCLA ✅; the three workflow runs are awaiting approval, could you approve them before/at the call? Looking forward to the 8:00 session — we'll take the optional slot in #471." Want me to post it (with the CLA attribution lines)?

@DovOps

DovOps commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator

Architectural feedback on whether this belongs in state 014 or a separate state 016:

My recommendation is to treat the currently implemented payment-intent handoff as an optional enhancement to state 014. A complete, demonstrable post-trade settlement workflow could justify its own state 016.

TraderX states are intended to be reproducible learning checkpoints, with explicit functional/non-functional deltas and comparable generated snapshots. This follows the state generation policy and generated-state branching ADR. The deciding question should be: what new concept does a learner understand after moving from 014 to 016? This is a proposed architectural criterion, rather than an existing rule about the minimum size of a state.

State 014 already teaches FDC3 context exchange, outbound intents, incoming workflows, graceful degradation, and repeatable Sail demonstrations. Adding another context type, another raiseIntent action, or another demo application extends that existing lesson. Reusable improvements to agent discovery, dispatch, diagnostics, and error handling also naturally belong in 014.

The intended post-trade scope could introduce a distinct lesson:

  • Mapping an execution to valid payment instructions, currencies, and counterparties.
  • Correlating the trade, payment request, and settlement receipt.
  • Preventing duplicate settlement requests.
  • Handling rejection, timeout, and uncertain outcomes.
  • Distinguishing payment/settlement status from TraderX's existing trade status.

Those are meaningful domain and integration boundaries, even if much of the implementation remains frontend code. A new backend service is not a prerequisite for a new state. However, a button that dispatches an intent does not yet demonstrate that lifecycle.

I suggest choosing one of these two scopes:

  1. State 014 enhancement: keep this as an optional payment-intent example, update 014's requirements and contracts explicitly, and include receiver registration, validated example payloads, degraded-mode behavior, and tests appropriate to the handoff. Keep the claims scoped to what the example demonstrates. Any change from 014's declared FDC3 2.2 target also needs explicit compatibility treatment.
  2. Separate post-trade state: make 016 a child of 014, preserve 014 as the FDC3 baseline, and implement the settlement-specific changes in 016's own overlay. Provide a reproducible request-to-outcome demonstration, ideally with a local mock receiver so the learning and tests do not depend on an external service. BankerX can be a reference adapter within a provider-neutral “Post-trade settlement interoperability” state. Complete the catalog, generation/runtime hooks, contracts, learning docs, and acceptance tests needed to make that state independently consumable.

The current arrangement mixes these scopes: it describes a separate settlement state, while the runtime changes live in state 014's frontend overrides. That means generating 014 acquires the settlement feature, and there is no clean generated 014 → 016 comparison showing the new lesson.

A numbered SpecKit feature pack does not automatically have to become a new runnable state; feature 015 (the documentation portal homepage) already illustrates that distinction. We can retain spec-first feature tracking without adding a checkpoint to the runtime learning path for every enhancement.

For this PR, I would resolve that scope decision before expanding the implementation: an additional FDC3 handoff example fits 014; a reproducible post-trade lifecycle earns 016.

@Synaptics-Lab

Copy link
Copy Markdown
Author

Thank you — this is exactly the review we needed, and we accept the child-state model.

Scope resolution — Option 2:

  • 016 becomes a child of 014. 014 stays the pristine FDC3 baseline, and the settlement runtime moves out of 014's frontend overrides into 016's own overlay. A generated 014 will no longer acquire the settlement feature, so the generated 014 → 016 comparison shows exactly one new lesson.
  • The lesson maps to your lifecycle list: mapping an execution to payment instructions, currencies, and counterparties; UETR-keyed correlation of trade ↔ payment request ↔ pacs.002 receipt; duplicate-dispatch prevention; rejection / timeout / uncertain-outcome handling; and settlement status (settlementState) taught as a concept distinct from trade status.
  • Local mock receiver. We'll add one so the request-to-outcome demonstration and tests are reproducible without any external service. BankerX stays as a reference adapter inside a provider-neutral "post-trade settlement interoperability" state, labeled testnet (XRPL altnet / Solana devnet).
  • This PR stops expanding. No new implementation here; the restructuring (overrides → 016 overlay, mock receiver, lifecycle demo and tests) lands as the 016 pack's own work, per the state generation policy and ADR-002. If you prefer, we can split this PR into two: the 016 spec pack as-is, and the 014-overlay cleanup as a follow-up.

One question before we start: for the generated 014 → 016 comparison, is the mock receiver the default receiver in 016's generated runtime (with BankerX as an opt-in reference adapter), or do you prefer both variants generated?

🤖 Generated with Claude Code

…of 014, mock receiver, findIntent-gated SETTLE

Resolves the maintainer scope review (state 014 vs 016):

- 014 restored to pristine FDC3 baseline: the payment-intent handoff no
  longer lives in 014's frontend overrides; generated 014 no longer
  acquires the settlement feature.
- 016 owns the settlement changes in its own overlay
  (generation/frontend-overrides/...): StartPayment dispatch,
  findIntent payment-receiver discovery, UETR dispatch tracking, and
  synaptic.settlementStatus correlation listener, layered on the 014
  baseline so the generated 014 -> 016 diff shows exactly one new lesson.
- SETTLE (BANKERX) action column is now capability-discovered: rendered
  only when fdc3.findIntent('StartPayment') resolves a participant;
  base TraderX (no post-trade participant) shows the pristine 014
  blotter. Availability re-probes on channel change and on a slow
  cadence; rows flip SETTLING... -> SETTLED / REJECTED by matching
  UETR; duplicate dispatch suppressed; failed dispatch reverts cleanly.
- Both receiver variants ship with the pack: local mock receiver as the
  DEFAULT (dependency-free, offline-reproducible demo + tests) and the
  BankerX settlement terminal as the opt-in reference adapter
  (app-directory URL swap, provider-neutral).
- Receiver-registration reference (mock-receiver/README.md +
  appd fragment) documents the intent-declaration contract that makes
  any guest participant resolvable via findIntent.
- Lifecycle smoke suite (tests/smoke/, 10 gates) runs the same
  provider-neutral module the mock receiver page uses.

Co-Authored-By: Claude Code <noreply@anthropic.com>
@Synaptics-Lab

Copy link
Copy Markdown
Author

Follow-up landing the restructure we agreed on, commit 68bb6cd:

Child-state model, executed

  • 014 is pristine again. The payment-intent handoff no longer lives in 014's frontend overrides — generated 014 no longer acquires the settlement feature, and a generated 014 → 016 diff shows exactly one new lesson (the lifecycle list from your review: execution → payment instructions, UETR-keyed correlation, duplicate-dispatch prevention, rejection/timeout handling, settlement status as a concept distinct from trade status).
  • 016 owns the settlement changes in its own overlay (specs/016-*/generation/), layered on the 014 baseline per ADR-002 and the generation plan.

Your call points, implemented

  • The button question — yes, and it's in: the SETTLE (BANKERX) action column is now capability-discovered via fdc3.findIntent('StartPayment'). Base TraderX with no post-trade participant renders the pristine 014 blotter; the column appears the moment a participant declaring StartPayment joins the workspace, and re-probes on channel changes. Exactly the workspace-availability behavior you described.
  • Both receiver variants: the local mock receiver is the DEFAULT (generation/mock-receiver/ — dependency-free, offline-reproducible demo + tests, with its app-directory fragment declaring StartPayment), and BankerX stays the opt-in reference adapter via an app-directory URL swap. The 014→016 lesson stays independent of any external service.
  • The dummy-guest 'not declaring a name' class of bug: generation/mock-receiver/README.md now documents the receiver-registration contract (appd record declaring the intent + name, runtime registering the listener) — same fix one-shot for any guest participant.

Verification: all root gates + state-pack/doc-consistency/lifecycle validators pass locally; docusaurus build exit 0; the lifecycle smoke suite (10 gates) runs the same provider-neutral module the mock receiver page uses — happy path, duplicate replay, honest rejection, rail-failure fallback.

🤖 Generated with Claude Code

Synaptics-Lab and others added 7 commits September 27, 2026 19:09
- Add standalone zero-dependency TraderX Spec 016 web execution blotter
- Implements FINOS FDC3 3.0 StartPayment intent dispatch to BankerX clearinghouse
- Implements direct on-chain Solana consensus verification via SPL memo instruction
- Add FDC3 App Directory manifest (appd.json) for desktop agent discovery
- Reference live deployment at https://traderx.synapticchain.xyz
…tus polling

- Auto-detect BankerX availability via periodic liveness probe
- Implement dual-channel FDC3 dispatch (postMessage + universal intent relay)
- Bind real Solana Token-2022 debtor and creditor accounts
- Add FDC3 status relay poller (500ms) with Solana tx explorer link rendering
- Guarantee seamless split-screen execution across browser windows
The demo estate had drifted to the legacy Spec 016 string
fdc3.paymentContext. PR #2204 proposes the exact context type
fdc3.payment with the StartPayment intent — align all Spec 016
artifacts (blotter, mock-receiver, appd records, angular override,
smoke tests, spec/plan/data-model/architecture docs) to emit
fdc3.payment, while receivers accept the legacy name inbound for
backward compatibility. Adds smoke gate H2 proving the legacy path.

Co-Authored-By: Claude Code <noreply@anthropic.com>
…tter

- estate-agent (fdc3-agent v9, esbuild IIFE): directory-miss fdc3.payment
  raises consumed at the transport tap before the web-impl sees them;
  screened through the Alcove enclave MCP preflight (sanctions bloom,
  Invariant-9 solvency, 256-lane rendezvous); delivered to the
  rendezvous-bound desk preferring the running BankerX instance;
  raiseIntentResponse carries intentResolution for the original
  requestUuid; honest RejectedByEnclave:<reason> failure path
- open() on the mcp-adapter record pings tools/list instead of
  window.open (no browser window for the adapter)
- index.html: SETTLE (ENCLAVE) button per EXECUTED row (targets
  bankerx-clearing-desk-eu, a directory miss); non-blocking intent
  modal (UETR/pair/channel/screen/desk/state) + pacs.002 receipt
  modal wired into both the Acsc and on-chain watcher paths
- E2E x2 green from identical bytes (10 gates): miss → screen-passed
  (lane 180, 5.93ms/3.08ms) → desk-delivered → ACSC; inbound 2,
  dup 0; modals both fire

Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
…w, 13-gate E2E

- estate-agent.ts: resolveRoutedDesk(lane) reads customProps.alcovePartitions
  and routes screened deliveries to the partition desk (running instance
  preferred, else normal FDC3 open path); delivered context carries the
  enclave WOTS+ proof + attestation timestamp for desk-side re-derivation;
  no more caller-supplied tsaFee/netAmount (canonical schedule is
  server-side); adapterRaises Map keyed by requestUuid (FIFO, cap 50)
- index.html: enclave demo targets bankerx-clearing-desk-geneva — a
  genuine directory miss (the eu desk is now a real record); ATTESTATION
  modal row on the intent modal; watcher path derives alcoveVerified
  fail-closed (on-chain memo implies desk-side verification) and updates
  the row itself since the 2.5s watcher wins the race vs status payloads
- e2e-alcove-adapter.js: 13 gates — adds routedDeskCorrect (partition
  lookup vs delivered desk), attestationVerified (desk console + VERIFIED
  row), rejectionHonest (sanctioned debtor → RejectedByEnclave);
  console capture on all popups

Proof: E2E ×2 exit 0 + FINOS conformance ×2 (129 pass / 7 fail, failure
list identical to runs 5-8) on identical deployed bytes.

Co-Authored-By: Claude Code <noreply@anthropic.com>
…nce set

Root cause of the FINOS mock-app close-chain failures (FindInstances,
RaiseIntentFailExistingInstanceRequired): instance-readiness desync.
findInstances responses were topped up with Pending (mid-handshake)
registrations, so closeMockAppWindow counted pages that had not yet
subscribed to the control channel (zero windowClosed echoes → wrong error);
raiseIntent at a just-launched instance hit the web-impl instant
TargetInstanceUnavailable in 3ms.

One mechanism — wait for reality:
- isAppConnected bounded-polls (≤2000ms, 50ms tick) a known-but-Pending
  instance; unknown instanceIds still return instant false (probe-verified).
- findInstances responses gate until every non-Terminated registration of
  the appId is Connected (≤2000ms), then recompute from the true set.
- closed-window sweep 1000ms → 250ms. Cache-buster ?v=11.

FINOS conformance ×2 on identical v11 bytes: 131 pass / 4 fail (runs 11/12,
393.68s/393.46s; mocha retry events account for the 4; DOM lists exactly one
failing test = the disclosed RaiseIntentFailTargetedAppInstanceResolve1
error-contract churn). E2E 13 gates ×2 exit 0 (runs 7/8).

Co-Authored-By: Claude Code <noreply@anthropic.com>
@DovOps

DovOps commented Sep 29, 2026

Copy link
Copy Markdown
Collaborator

Hi @Synaptics-Lab — thanks for the work since our September 25 discussion. Having reviewed the direction and thought more about the learning experience, I’d like to clarify my earlier feedback.

I now think a dedicated state 016 is the right direction, with 014 preserved as the general FDC3 interoperability foundation. I don’t think we need a separate BankerX enhancement to 014 first.

The reason is that even a simple payment-intent button requires us to explain what happens after trade execution: what obligation remains, why TraderX hands it to BankerX, and what a settlement result means. Splitting the connection from that explanation would fragment the lesson. Instead, the FDC3 handoff can be the opening step of a coherent new state: “Post-trade settlement with BankerX: an introduction to blockchain settlement.”

The learning experience

Let’s assume the reader understands TraderX but knows little about blockchain settlement. The walkthrough should answer:

  1. What remains after execution? Identify the parties, the assets or currencies owed, and the obligation being settled.
  2. What does TraderX send to BankerX? Explain the payment instruction, the FDC3 handoff, and how the request is tied to the original trade.
  3. What does BankerX do? Introduce the chosen settlement mechanism and clearly distinguish simulated behavior from actual testnet activity.
  4. What comes back? Show success, rejection, and pending or unknown outcomes in TraderX, explaining what evidence supports each result.

Please also clarify whether the example demonstrates securities delivery-versus-payment, currency payment-versus-payment, or a payment transfer. The terminology should match the actual flow and the legs it demonstrates.

A focused first version

I’d like the first version to demonstrate one understandable, reproducible path:

Execute an example trade in the existing TraderX application → request settlement through FDC3 → process it in BankerX → return a correlated outcome to TraderX.

A working local mock should let contributors learn and test the request/receipt flow without external infrastructure. BankerX can then demonstrate the blockchain testnet implementation through the same documented interface.

The standalone web blotter is useful supporting material, but it shouldn’t substitute for demonstrating the integration with the existing TraderX application. Likewise, multiple rails, a custom desktop agent, and enclave routing can be follow-on work unless they are essential to the initial lesson.

What needs closing before that demonstration is ready

Our latest local evaluation found several gaps worth prioritizing:

  • The Angular overlay still fails compilation on Account.name, and its payment mapping still uses the security ticker as currency.
  • The local mock needs to connect to the actual desktop agent; its current in-page stub does not demonstrate a Sail round trip.
  • The generation/startup instructions need to work from a clean checkout.
  • Duplicate requests, receiver failures, and unknown outcomes need reliable handling. An explicit rejection should not fall through to another dispatch path.
  • Connection and settlement indicators should describe what has actually been established. Endpoint availability is not a connected receiver, and a matching ledger memo alone does not establish the complete settlement outcome.

These are implementation gaps to resolve within the proposed direction, rather than reasons to move the feature back into 014.

My suggested next step is to agree on a short learning outline and one acceptance-demo script before expanding the implementation further. That will give us a shared definition of what state 016 teaches and what a reviewer should be able to reproduce.

This refines my earlier suggestion: keep 014 intact, make 016 the BankerX settlement lesson, and make the first delivery simple enough for someone new to the subject to follow from trade to outcome.

@Synaptics-Lab

Synaptics-Lab commented Sep 29, 2026 via email •

Copy link
Copy Markdown
Author

Synaptics-Lab and others added 8 commits September 30, 2026 14:26
…s/channels/broadcast), window.fdc3 preload, SPA-param snapshot

LoopbackDA becomes a real FDC3 protocol client: pending-map multiplexer,
addIntentListener/addContextListener/broadcast/getCurrentChannel/
getUserChannels/joinUserChannel/leaveCurrentChannel/getInfo over the
web-impl message types. Agent publishes window.fdc3 (Desktop Agent
Preload, yields to existing hosts) and fires fdc3Ready. Boots-params are
snapshotted at parse time so the Angular router's ?query strip cannot
drop ?directory/?launcher. Frozen estate bytes unaffected — v12 emits
fdc3-agent-v12.js only (build-v12.mjs), deployed to /angular/ alone.

Co-Authored-By: Claude Code <noreply@anthropic.com>
…record, ?v=12 agent reference)

Co-Authored-By: Claude Code <noreply@anthropic.com>
…(duplicate-suppressed settle dispatch) + deploy md5 registry

Co-Authored-By: Claude Code <noreply@anthropic.com>
…pping) — pristine + pre-patch evidence moved out of web root, PATCH-NOTE.md

Co-Authored-By: Claude Code <noreply@anthropic.com>
…and the package is type:module

Co-Authored-By: Claude Code <noreply@anthropic.com>
…cket source

The +633B onCreate injection that existed only in the served minified
bundle (main-SZ7POL5E.js) is now real TypeScript: onCreate() normalizes
the selected company to USD/KES / EUR/USD and otherwise routes through
Fdc3TickerCompatibilityBridgeService.normalizeTicker (canonical location).

Also lands the tree deltas needed to reproduce the deployed build exactly:
- fdc3-interop.service.ts (016 pack + estate resolveAgent fast-path)
- Account.name? / Trade.price? (used by the settle flow)
- @robmoffat/fdc3-get-agent dep + skipLibCheck (broken packaged .d.ts refs)

Deployed main-ZMJ5JEK4.js fingerprint-matches the previously served bundle
on every estate marker; hand-patched copy archived as evidence.

Co-Authored-By: Claude Code <noreply@anthropic.com>
… registry

Co-Authored-By: Claude Code <noreply@anthropic.com>
…e blotter

- fdc3-interop.service.ts: refreshPaymentReceiverAvailability now parses the
  FDC3 wire shape {appIntent:{intent,apps}} (what the estate DA actually
  returns) in addition to {apps}/{appIntents} — the SETTLE column was
  deterministically gated off because the probe read apps off the wrapper.
- trade-blotter.component.ts: initialize the FDC3 interop service on blotter
  mount — nothing on the plain blotter view triggered agent resolution, so
  the availability probe (and the whole SETTLE column) never ran.
- estate-agent.ts open(): launch desk as a SEPARATE OS popup window sized to
  ~52% viewport positioned right (side-by-side demo), not a browser tab.
- trade.component.scss: fluid min-width min(700px,100%) on blotter/position
  containers — page no longer forces 753px on phone/tablet widths; ag-grid
  scrolls columns internally.
- build-v12.mjs: drop stale v11-freeze note (estate unfroze 2026-09-30).

Deployed bytes: main-WFYOIDOI.js (e2026b01 parent fix set: main-7LUE5SFM
superseded same day), agent b600a533 ?v=15 both surfaces, index glue tags
re-added. Live-verified pre-batch: SETTLE renders, desk popup 666px offset,
no page overflow at 390/620 on either surface.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Settlement truth must outlive the page that witnessed it — durable
UETR-keyed adapter registry, fingerprint-guarded adoption, chain-memo
witness at the reconciliation seam, intent-availability gating,
desk-reuse, shared compliance path, build-source alignment gate.

Co-Authored-By: Claude Code <noreply@anthropic.com>
@Synaptics-Lab

Copy link
Copy Markdown
Author

v20 on the angular blotter — durable settlement ledger (d4397fe..5b130bd), closing the "settled state is per-browser" defect

Operator-reported defect on the running angular surface: opening another
browser reset already-settled rows back to SETTLE buttons, and some rows
stayed stuck on SETTLING… after BankerX settled them. Root cause, verified
in code before the fix: the settlement ledger lived only in
localStorage (per-browser), and the adapter served every trade from
in-memory lifecycle state while holding no settlement status — the single
browser that witnessed a settle was its only witness.

Fix — three pieces, minimal delta:

  1. Adapter durable registry (file-backed, keyed by UETR). GET/POST
    …/trade-service/trade/trades/settlements/. One-way ISO 20022 ordering
    (Pndg → Acsc/Rjct) enforced server-side and in the blotter as before.
  2. Blotter publish + reconcile — every lifecycle transition publishes
    (entries carry the trade fingerprint: security, quantity, side, created);
    each browser reconciles on load, on a 3s tick, and when new rows land.
    Adoption is fingerprint-guarded: own-UETR match, or full fingerprint
    match. A trade re-seeded after an adapter restart (new created) is
    correctly not adopted — demonstrated live, not asserted.
  3. Chain-truth at the reconciliation seam — a row stuck on SETTLING…
    whose only witness page missed the live broadcast resolves from the
    settlement transfer's own memo (the UETR sits inside the SPL memo of
    the transaction that itself moved the funds, observed on the creditor
    token account). Addressing the point in the Sept-29 review directly: this
    is not a separately-posted ledger record standing in for outcome
    evidence — it is the transfer's own memo, corroborated by the desk's
    WOTS+ side attestation, and a failed attestation creates no settlement
    and therefore no memo.

Verification, all on one deployed byte set (main-FDMPPVWA.js
ca10adb4…, bundle ref ?v=20):

  • Angular conformance ×2 on identical bytes: 131/1 (sole failure the
    previously-disclosed RaiseIntentFailTargetedAppInstanceResolve1 churn)
    then 132/0; angular E2E ×1 all gates PASS. (As before, mocha's
    FINAL STATS overcount — DOM counts are the truth.)
  • Cross-browser probe with real settles: browser A settled a row (tx
    62akSM7RWWHmK3XW5FAi3GjDLSEQThwp9XWkQDLFNv5ngmp4d32rWtULEDZaiDJ5AcoFBsgbrV9iXMjWuWprxhPk);
    a fresh second browser — zero shared storage — showed the row SETTLED on
    fresh load and after reload. Second probe: settlement (tx
    hkie33K93cXH8i2E2kQiwN2X1FZ68RQS3594JcrTXdFLRXsbjcL593HaiMczGPxhv5RFhiiVvtBb5r5VK8Fxkoz)
    survived an adapter restart via the registry.
  • Read-only demo preflight on these bytes: 25/0.

Also on the branch in this range: desk-reuse (d4397fe) — pressing
SETTLE reuses and focuses the already-open BankerX desk window instead of
opening a duplicate tab (real window identification in the desktop agent).

Against the Sept-29 review's gap list, this closes the last items in the
running app: unknown/late outcomes now self-cure (registry reconcile ~3s,
chain memo ~2.5s), and the connection/outcome indicators still describe what
is actually established (the acceptance harness asserts a real WCP round
trip, and the offline receiver's Acsc remains clearly labeled simulated in
the acceptance flow).

Your Sept-29 suggested next step — agree the short learning outline and one
acceptance-demo script — was delivered on the branch (learning outline +
acceptance-demo.md, clean-checkout proof, 10/10 ×2 harness). The outline in
comment 5895905019 remains the proposed first-version scope: if it looks
right (or needs re-cutting), say the word and we proceed on your
confirmation.

Synaptics-Lab and others added 7 commits October 4, 2026 19:24
…n honesty, held authorization

- estate-agent: synth raise into a not-yet-Connected desk window is no longer
  claimed as delivered ('desk-delivered ... instanceId null' traced while every
  real desk window sat idle — trade stayed SETTLING forever). The adapter now
  waits up to 8s for a desk instance to reach Connected (findOrAwaitDeskWindowFor)
  and throws no-connected-desk-instance when nothing did, so the caller's legacy
  dispatch channels (postMessage + relay bus) carry the payment instead.
- blotter (FR-01607 release): a desk-side Rjct now releases the dispatched-UETR
  guard, surfaces the reason (row title + FDC3 log + toast), and renders
  REJECTED rows as re-dispatchable (SETTLE buttons return on RJCT rows).
- blotter (raise-fallback honesty): the raiseIntent catch no longer hides the
  intent modal — the modal states 'DA RAISE FAILED — LEGACY DISPATCH' so the
  operator sees the postMessage + relay-bus fallback instead of a window that
  appears to self-close.
- blotter: reason field plumbed from both status transports (opener
  postMessage + /api/fdc3/status relay) into applySettlementStatus.

Co-Authored-By: Claude Code <noreply@anthropic.com>
…rejection honesty, held authorization"

This reverts commit 0248cca.
…ent v20)

The BankerX desk's F-8A-hardened verify_preflight requires the Ed25519
signature fields and refuses unkeyed attestations; the adapter was still
dropping them from the delivered alcove block, so every enclave-routed
StartPayment honest-rejected desk-side. The estate-agent now parses
ed25519SignatureSample / ed25519PublicKeyHex / signedMessageHex from the
preflight report and carries them in the delivered context (both intercept
sites). Verified live x2 on traderx.synapticchain.xyz: desk logs
"Attestation verified desk-side (WOTS+ leaf root re-derived, lane 180)",
inbound StartPayment auto-executes, blotter row ACSC with the settlement
ticket CONFIRMED (TSA levy netted).

Trace fix: the desk-delivered trace awaited awaitConnectedInstanceForAppId
before recording, so the instanceId is the real WCP instance instead of a
premature null (the delivery actually lands via the pending-intent queue
~0.8s after raise).

Record sync: the deployed /var/www/traderx/index.html (desk-reuse guard
variant, agent ref ?v=12) is now the committed source of the root blotter
record; angular-deploy.md5 table updated (agent bdc3a82b, root index
b2e50f92, angular index 76e6662e).

Co-Authored-By: Claude Code <noreply@anthropic.com>
…urface

Operator ruling (2026-10-05): the settle path's blind window.open fallback
spawns an unwired duplicate BankerX tab whenever no desk window is tracked
(e.g. settle-without-launch); the FDC3 raise cold-launches the desk as the
wired popup window itself, so the tab was never part of the delivery path.
Removed — the settle path now reuses the agent-tracked desk window when on
e exists and otherwise logs that the raise cold-launches the wired window.

Verified live x2 on fresh profiles: openLog contains exactly one window per
settle (popup features, bankerx-clearing-desk-eu-<instanceId>), the
attestation still verifies desk-side, delivery lands (desk-delivered with
the real instanceId), and the blotter row settles ACSC.

Deployed index is the record: /var/www/traderx/index.html md5 5144d7bd =
committed generation copy (agent ref ?v=12, agent bytes bdc3a82b unchanged).

Co-Authored-By: Claude Code <noreply@anthropic.com>
The settle context carried the legacy debtor ATA 4cghWNxg... (closed by the
2026-10-03 F-10A rotation) and the Solana creditor ATA — rail accounts mas-
querading as party identities in the FDC3 wire shape. Replaced with the REAL
key-backed syn1 desk identities from the live registry (/api/identity/desks,
sha3-256(pub)[12..32]): traderx syn13ln3v..., bankerx syn1a4jwm.... The
desk's resolveInboundAccount passes checksum-valid syn1 straight through, so
the resolve route changed from registry-name match to identity pass-through —
proven x2 live on fresh profiles (UETRs 111d089f.../5219dea9...): delivery
lands, single wired popup, attestation verified, ACSC both. Rail accounts
stay where they belong: token2022-config.ts.

Co-Authored-By: Claude Code <noreply@anthropic.com>
…(estate-open-gaps finos#1)

A blotter row whose StartPayment dispatch failed/landed nowhere sat in
SETTLING | DISPATCHING forever with no truth and no path out. Fixed:
a 120s dispatch-timeout sweep converts a stranded SETTLING row to
REJECTED with the honest reason ('dispatch timeout (120s) — intent
never reached a desk'), releases the FR-01607 duplicate-dispatch guard
so the UETR is re-raisable, and renders a RE-DISPATCH handle. Re-dispatch
rewinds to EXECUTED and re-runs the same settle raise; if the original
intent actually landed late, desk UETR dedup + the settle-gate claim
still refuse the duplicate. Late-landing Acsc still overrides the
timeout label (applySettlementStatus accepts Acsc for REJECTED rows) —
timeout labels never beat money truth. No hold-card, per operator ruling.

Functional proof: playwright probe against repo bytes (desaf listener
swallow = lands-nowhere shape) — SETTLING after dispatch, RJCT + reason
+ guard-release after ~120s, RE-DISPATCH re-arms SETTLING. Acceptance
harness pass/fail set IDENTICAL to HEAD baseline (8/10 both; acsc +
receiptModal pre-existing environmental gates, bounded to the day-one
origin-mismatch between harness receiver and the live relay).
@DovOps

DovOps commented Oct 11, 2026

Copy link
Copy Markdown
Collaborator

Hi @Synaptics-Lab — thank you for contributing this work and for the substantial follow-through since the September 25 discussion. The clearer cash-leg explanation, acceptance walkthrough, source-build fixes, receiver registration and desk reuse are useful progress. I still support a dedicated state 016, building on 014, with the FDC3 handoff as the opening step of an understandable post-trade settlement lesson.

I've refreshed our local evaluation against 119ef80. Here is a consolidated review status, including a learning-portal integration gap we found.

What we verified

  • The submitted Angular template builds; the supplied lifecycle smoke passes 11/11.
  • The local mock connects to a real desktop agent and receives StartPayment.
  • In our refreshed Sail workspace, two successive settlement requests reached the same existing mock panel. Receiver reuse worked in this test.
  • The spec now explains cash-leg payment transfer rather than claiming securities DvP/PvP. Please also align the PR title/description and standalone UI terminology with that scope.

Our Angular evaluation layers the current settlement changes onto an existing generated 014 runtime, retaining its pricing/ticket/NATS integration. It is therefore a local integration evaluation, not proof of a clean 016 generation. We also exercised the submitted standalone acceptance pages. External relay/RPC connections were blocked for the local mock evaluation; we did not independently rerun your hosted conformance or real-chain settlement results.

Learning integration — please include this in #470

The spec pack appears in the automatically discovered Specs section, but 016 is absent from catalog/state-catalog.json, so the generated Learning section and Visual Learning Paths omit it. Our existing checks missed that omission; this is also a repository-wide checks gap, not just a request for more prose in this PR.

I've opened #474 against main for the reusable parity checks. For this PR, please:

  • Register 016 with 014 as its parent and an honest readiness status. Do not imply a published generated-code branch before one exists.
  • Add it to specs/README.md, run bash pipeline/refresh-state-docs.sh, and include the resulting learning guide, indexes/catalog and visual graph changes.
  • Add the Learning sidebar entry in website/sidebars.js.
  • Make the lesson explain the obligation remaining after execution, payment instructions and UETR correlation, what the local mock simulates, what the optional BankerX testnet adapter actually verifies, and how success/rejection/unknown outcomes appear in TraderX.

This screenshot is a proposed local example, showing 014 → experimental 016. It is not a claim that 016 is already accepted or published:

Local learning-map example showing state 012 branching to 013 and 014, with experimental state 016 beneath 014

Acceptance items still open in the committed/local path

  • Complete the receipt round trip. The mock showed Acsc — SETTLED, but the originating standalone/Angular rows stayed SETTLING. In Sail this happened for both requests even though the existing receiver was reused. The mock's channel.broadcast writes to its private in-page array rather than the connected agent; its opener message also conflicts with the standalone blotter's hosted-origin filter. Please test the originating row and correlated outcome, not only receipt of the intent. (Mock return path, origin filter.)
  • Use valid payment instructions. A sample BAC equity trade produced currency: BAC, pair: BAC/KES, and amount 14020.964999999998; the mock accepted it. Define the cash currency, parties, amount/rounding and eligible trade fixture explicitly, and reject invalid instructions. (Currency mapping.)
  • Make startup and persistence reproducible. The 016 start script generates/starts the 014 baseline without applying the full 016 Angular overlay, and registers a mock URL on the Sail port without serving that pack there. Its default dry-run path also invokes generation before the dry-run guard. Separately, the standard frontend calls /position-service/trades/settlements/, which returns 404 on our backend; your notes describe a separately deployed adapter at a different endpoint. Please include or pin/document that dependency and wire its configuration so a reviewer can reproduce reload, second-browser and restart behavior.
  • Preserve the earlier states. Settlement-specific behavior now also lives directly in the shared Angular templates. Please keep that behavior in the 016 overlay and demonstrate that generating 014 preserves its baseline, with a clear generated 014 → 016 comparison.
  • Close the negative-path gaps. Additional receiver probes found simultaneous requests with one UETR could invoke the rail twice, and thrown rail errors escaped outcome handling. The standalone dispatch catch also falls through to legacy dispatch after an agent rejection. Please cover concurrent deduplication, thrown errors/uncertain outcomes, and explicit rejection without redispatch through another route.
  • Match settlement claims to verified evidence. The committed reconciliation code promotes rows after a signature memo contains the UETR. Please either verify transaction success and the expected asset, amount and counterparties, or document and reproduce the trusted adapter/attestation boundary that establishes those facts. The hosted proof described above is useful context, but we still need that guarantee reproducible from the contributed setup. (Memo reconciliation.)

The next acceptance target remains one clean-checkout path: existing Angular TraderX → FDC3 → local mock → correlated outcome back in TraderX, including rejection/unknown outcomes and documented persistence behavior. Once that passes, the optional BankerX blockchain demonstration can build on the same contract.

I'm keeping this review status here in the PR discussion. The public learning portal should contain the durable lesson and reproducible walkthrough, not a PR-specific evaluation report. Thanks again for bringing this concept into TraderX and continuing to work through the integration details.

…r to github.com/Synaptics-Lab; protocol-spec links to public x402-tswp
…ent, experimental), generated learning guide + indexes, sidebar entry

Per maintainer review (finos#470, DovOps 2026-10-11): 016 was absent
from catalog/state-catalog.json, so the learning section and visual learning
paths omitted it. Registered with 014 as parent and status experimental — no
published generated-code branch is claimed (no publish block; guide renders
'n/a'). The lesson content is sourced from a new functional-delta.md explaining
the cash-leg obligation, the fdc3.payment instructions + UETR correlation, what
the local mock simulates vs what the BankerX adapter verifies, and outcome
rendering. Runs green under the merged learning-parity gate (finos#474) and
verify-spec-coverage.sh. Also merges upstream main (finos#473, finos#474) into the branch.
…listen

Mock receiver: emission is single-sourced through the connected WCP agent
(join default user channel, broadcast the pacs.002-shaped context) with the
opener postMessage relay demoted to a disclosed fallback and the stub
channel display-only. The stub array never flips a row — that was the
acceptance defect.

Standalone blotter: accept same-origin relay messages only from the pack
origin, and register the synaptic.settlementStatus context listener on the
desktop agent (polling for the asynchronously-published agent, joining the
default user channel first) so channel broadcasts reach the host listener
under FDC3 2.0 delivery semantics. Idempotent with the postMessage path;
applySettlementStatus short-circuits on settled rows.

Evidence: acceptance/harness 10/10 twice (FIX3, FIX3b); baseline before the
fix was 8/10 (acsc, receiptModal failing).
A BAC equity trade produced a payment instruction with currency 'BAC',
pair 'BAC/KES' and amount 14020.964999999998 — an instrument symbol passed
off as a currency and a drifted float on the wire (DovOps consolidated
review of finos#470, open item: valid payment instructions).

New mapping module (generation/payment-instruction.mjs, typed mirror in the
Angular blotter overlay):
- FX pair securities settle their base leg, rate = the execution fill
- equity securities settle a same-currency venue (KES) transfer of the
  minor-unit-rounded notional — pair/rate omitted, no FX data invented;
  float drift (14020.965 as 14020.964999999998) is epsilon-corrected
- parties follow the trade side: the buyer owes the cash
- unsettleable securities (bare currency codes, malformed pairs) are
  refused before dispatch

Receiver validator tightened (mock-receiver/payment-lifecycle.mjs + vendored
blotter copy): currency must be an active ISO 4217 code ('BAC' is
alpha-3-shaped but not a currency); pair/rate are a strictly coupled
optional frame — lone pair, lone rate, and pairs with non-currency legs are
refused. The Angular interop service ships the FX frame on the wire only
when both halves exist.

FR-01603 rewritten to define the cash-leg mapping, rounding, and party
direction. New smoke suite tests/smoke/payment-instruction.test.mjs pins
the BAC defect case end to end (11/11); lifecycle suite updated for the
renamed/tightened reasons (11 gates); acceptance harness keep-green 10/10
twice after the validator change.
DovOps consolidated review item: 'Preserve 014: settlement behavior must
stay in the 016 overlay; prove clean 014 generation with a 014-016
comparison.'

The shared speckit generation base (templates/web-front-end/angular) carries
no 016 settlement code anymore: fdc3-interop.service.ts (file, branch-only)
and the trade-blotter / position-service / account-model / trade-model deltas
are reverted to the upstream merge commit, and the pack overlay provides all
of them as full-file overrides instead.

The 014 -> 016 comparison is now a runnable proof:
tests/smoke/generated-tree-purity.test.mjs replays the generation
composition statically and asserts the upstream 014 composition is
settlement-free (Q1), that today's templates tree composes byte-identically
under main/app to the upstream composition (Q2), and that the 016 overlay
adds the settlement surface back exactly where the overlay says (Q3).
4/4 gates, green twice.
…ependency

DovOps consolidated review item: '016 start script generates 014 without
the full 016 Angular overlay; dry-run generates before guard; the
/position-service/trades/settlements/ dependency must be documented/pinned.'

- Step 2: the 014 generation command is printed under --dry-run, never
  executed (previously it ran before the guard - a validation-only run
  rewrote the generated tree).
- New step 2b: the pack's full frontend overlay (settlement blotter, interop
  service, settlement-registry client, desk model extensions) is applied on
  top of the generated 014 angular tree with the state renderers' cp -R
  idiom, and the FDC3 agent dependency pins are enforced exactly as
  render-state-014 pins them (fdc3-get-agent 2.2.2-beta.3, uuid ^14.0.0).
- Baseline artifact validation degrades to [dry-run][warn] under --dry-run
  and a clean checkout now completes with [done] after printing every
  runtime action (delegation included) with exit 0; docker absence warns
  instead of failing validation-only runs.
- New step 2c: the settlement-registry dependency is checked at
  SETTLEMENT_REGISTRY_URL (default :8415 adapter) with an honest degraded-
  mode warning; quickstart.md documents the dependency and the 404-poll
  degradation contract.

Proven: plain and --static --dry-run both end [done] exit 0 from the repo
root.
DovOps acceptance review, negative paths:

- Concurrent same-UETR double rail invocation: PaymentReceiver serializes
  in-flight receives per UETR (the settlements check alone only guards after
  the first outcome lands). A second concurrent receive awaits the first
  outcome and replays it marked duplicate — the settlement rail runs exactly
  once.
- Thrown rail errors escaping outcome handling: rail.settle is wrapped in
  try/catch; a crashing rail is an honest Pndg with a 'rail error:' detail
  naming the rail — receive() never rejects, and a fake Acsc is impossible.
- Agent rejection falling through to legacy redispatch: a raised-but-rejected
  intent is a dispatch OUTCOME in the standalone blotter — the row goes RJCT
  with the real reason and the dispatch guard releases; legacy channels
  (postMessage/relay) stay reserved for the no-agent case (FR-01605) instead
  of refiring the same UETR.

Angular counterpart verified already correct: raalseStartPayment's catch
returns false and the blotter reverts the row (settlementByRow cleanup),
no legacy redispatch either.

Tests: lifecycle smoke K (concurrent same-UETR, rail invoked once), L
(throwing rail → Pndg, receive() resolves), M (vendored mirror byte-sync).
Suites: lifecycle 14/14, payment-instruction 11/11, purity 4/4, ×2;
acceptance harness 10/10 ×2.
DovOps acceptance review, claims vs evidence: the receipt modal previously
declared 'pacs.008 memo verified' unconditionally, including settlements
that arrived from the mock receiver with no transaction behind them.

- Receipt modal now classifies the settlement's evidence: a row with a
  txSignature (Solana devnet memo watcher — the ledger itself read back)
  is labeled on-chain; an Acsc with no tx signature is labeled
  'counterparty Acsc — no tx evidence (mock/demo boundary)'. The RAIL row
  is no longer hardcoded Solana: broadcast-only settlements name their
  actual rail.
- Blotter log states plainly when an Acsc carried no tx evidence.
- Mock receiver card marks simulated settlements with a demo-rail badge;
  rail/dispatch fields already echoed for operator review.
- spec.md §0b documents the three status channels' differing evidence
  strengths, the adapter/attestation trust boundary (demo adapter is
  unauthenticated, file-backed; only the ledger path verifies tx success),
  and names the production closure (signed pacs.002 / ADR-555 attestation)
  as out-of-scope rather than faking it.
- quickstart.md §5 adds the boundary to the verification notes.

Suites: smoke lifecycle 14/14, payment-instruction 11/11, purity 4/4 ×2;
acceptance harness 10/10 ×2.
@Synaptics-Lab Synaptics-Lab changed the title feat(fdc3): add BankerX DvP settlement adapter and ISO 20022 pacs.008/pacs.002 reference flow (Spec 016) feat(fdc3): post-trade cash-leg payment transfer — StartPayment → pacs.008/pacs.002 reference receiver (Spec 016) Oct 12, 2026
Remove the Colosseum banner and estate verification table from the
project README — that content is estate marketing and does not belong
in a FINOS upstream surface; it lives in the contributor's own
repositories. Adds an upstream-pristine smoke test so a contribution
cannot reintroduce marketing tokens, embedded banners, or root-level
banner files past this point.
@Synaptics-Lab

Copy link
Copy Markdown
Author

Apologies — and the cleanup is pushed (head 7263f21).

An earlier commit in this PR embedded a banner image and an estate verification table into the project README, and added a colosseum-2026-banner.svg at the repository root. That was estate marketing inside FINOS's upstream surface — it should never have been committed here, and I should have caught it myself before anyone else had to.

What this commit does:

  1. README.md is restored to the upstream original — banner embed, third-party blockquote, and the verification-score table are gone. Byte-identical to main.
  2. colosseum-2026-banner.svg is deleted.
  3. A new smoke test in the 016 pack — specs/016-post-trade-settlement-bankerx/tests/smoke/upstream-pristine.test.mjs — now fails the build if any estate marketing token, embedded banner, or root-level banner file re-enters an upstream surface, so this is structurally prevented, not just cleaned up. All four 016 smoke suites pass with it (run twice).
  4. One wording fix in the 016 pack's vendored PATCH-NOTE.md (a stray "judges" became "reviewers").

The 016 spec delta itself — cash-leg transfer, receiver hardening, purity tests, evidence classification — is unchanged from the review state. Thank you for bearing with the extra commits; the branch is cleaner for your next evaluation than the last one.

This branch has not been deployed

No deployments
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