Repository navigation
feat(fdc3): post-trade cash-leg payment transfer — StartPayment → pacs.008/pacs.002 reference receiver (Spec 016) - #470
Conversation
…/pacs.002 reference flow (Spec 016) Signed-off-by: Abdul Shabazz <veritasvaultone@gmail.com>
✅ Deploy Preview for lucky-concha-f3599f ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
One or more co-authors of this pull request were not found. You must specify co-authors in commit message trailer via: Supported
Alternatively, if the co-author should not be included, remove the Please update your commit message(s) by doing |
|
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
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! |
…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>
54a9f52 to
1d85569
Compare
|
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)? |
|
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 The intended post-trade scope could introduce a distinct lesson:
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:
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. |
|
Thank you — this is exactly the review we needed, and we accept the child-state model. Scope resolution — Option 2:
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>
|
Follow-up landing the restructure we agreed on, commit Child-state model, executed
Your call points, implemented
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 |
- 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>
|
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 experienceLet’s assume the reader understands TraderX but knows little about blockchain settlement. The walkthrough should answer:
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 versionI’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 readyOur latest local evaluation found several gaps worth prioritizing:
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. |
|
Hi @DovOps —
Thanks for the local review and for confirming that dedicated State 016
(“Post-trade settlement with BankerX: an introduction to blockchain
settlement”) is the right architectural direction.
To align on the learning experience before pushing updates, here is our
proposed Learning Outline and Acceptance Flow:
1. State 016 Learning Outline: The Cash Leg of Trade Settlement
* The Cash Leg: Why trade matching in TraderX is only half the trade;
explains the counterparty risk remaining before settlement finality.
* The FDC3 Hand-Off: Why front-office blotters delegate clearing via
standard StartPayment (fdc3.payment + SWIFT gpi UETR) rather than holding
blockchain keys.
* BankerX Execution: How the settlement desk verifies pre-flight compliance
(<8ms) and settles the trade's currency cash leg on-chain (the cash leg of the executed trade; securities DvP is out of scope for this state).
* The Settlement Receipt: How the returned ISO 20022 pacs.002 updates the
blotter row from PENDING to SETTLED.
2. Code Remediation
* Clean Angular Build: Fix Account.displayName typing and decouple currency
(USD) from ticker symbol (security).
* Desktop Agent Handshake: Direct browser FDC3 dispatch via Sail Desktop
Agent with clean fail-closed error handling (no fallback cascades).
* Clean Checkout: Verified npm install && npm start workflow with zero
assumed local dependencies.
Does this outline and acceptance scope work for you? Once you give the
thumbs up, we will push the changes to update the PR.
… Message ID: ***@***.***>
|
…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>
|
v20 on the angular blotter — durable settlement ledger ( Operator-reported defect on the running angular surface: opening another Fix — three pieces, minimal delta:
Verification, all on one deployed byte set (
Also on the branch in this range: desk-reuse ( Against the Sept-29 review's gap list, this closes the last items in the Your Sept-29 suggested next step — agree the short learning outline and one |
…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).
|
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
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 #470The spec pack appears in the automatically discovered Specs section, but 016 is absent from I've opened #474 against main for the reusable parity checks. For this PR, please:
This screenshot is a proposed local example, showing 014 → experimental 016. It is not a claim that 016 is already accepted or published:
Acceptance items still open in the committed/local path
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. |
…2 test census + receipted suite scores)
…r to github.com/Synaptics-Lab; protocol-spec links to public x402-tswp
…roprietary source)
… previews + learning-parity CI gate
…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.
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.
|
Apologies — and the cleanup is pushed (head An earlier commit in this PR embedded a banner image and an estate verification table into the project README, and added a What this commit does:
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. |

PR Description
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
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).raiseStartPayment(paymentContext)infdc3-interop.service.tsdispatching the standardizedfdc3.paymentintent context (per FINOS PR #2204).position.service.tsGET/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.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.payment-lifecycle.mjs) withvalidatePaymentContext(ISO 4217 currency admission, coupled optional pair/rate frame for FX legs, complete debtor/creditor, networkRouting) and aPaymentReceiverthat serializes concurrent same-UETR receives (the settlement rail runs exactly once; losers replay the first outcome marked duplicate), catches thrown rails as honestPndg(rail error: …, never a fakeAcsc), and never rejectsreceive().txSignaturefrom the ledger-read-back path shows the on-chain verification; a broadcast-onlyAcscis explicitly labeledcounterparty Acsc — no tx evidence (mock/demo boundary). No claim is presented as on-chain proof when it is not.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
./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-runalso supported and validated to complete from a clean checkout).payment-instruction.test.mjs— 11 gates (currency mapping, minor-unit rounding, receiver-side validator).lifecycle-mock-receiver.test.mjs— 14 gates (schema, duplicate replay, honest rejection, concurrent same-UETR, thrown rails, mirror sync).generated-tree-purity.test.mjs— 4 gates (generation purity proof).?launcher=1&directory=<appd-url>flow.SETTLE (BANKERX).fdc3.paymentwith the UUIDv4 UETR, and the pacs.002-styleAcscstatus round-trip flipping the originating row (FR-01605/01604/01606).4. Checklist
fdc3.paymentper PR #2204).ViewOrders,ViewChart,ViewQuote).