Changelog
Contract releases with what integrators must do, newest first. Current contract: 1.0.0-draft.14. Deprecated operations are listed on Deprecations.
API contract
1.0.0-draft.14
(2026-09-24, Phase 10 close-out review: 526 paths, 660 operations, 849 schemas). One additive enum value for integrators; the rest tightens staff operations:
- Neutral review holds.
Hold.subject.typeaddspayment_review: funds reserved while a payment is processed (for example an incoming credit under review). Itssubject.idis the hold's own id and its description is neutral; the amount counts against the available balance like any other hold. Clients that switch on the subject type should treat unknown values as a generic reservation. - Step-ups on policy writes (staff).
PUT /operators/{operatorId}/settingsneeds themfa.changestep-up when it changessecurity,approvedEmailDomainsorapiKeyInvitationDomains.PUT /platform/compliance/defaultsneeds the new capabilityplatform.compliance, anX-Access-Reasonand thecompliance.gate_settings_changestep-up. - Status unsubscribe limit.
POST /public/status/subscriptions/unsubscribeis limited per unsubscribe token (5 an hour), not per address, so mail providers' one-click unsubscribes are never refused for sharing an address. - New capability.
platform.compliance(WireBloom super admins).
Also in draft.14 (2026-09-25, Phase 11/12 residual wave: 529 paths, 664 operations, 856 schemas). Additive: no operation, schema or property was removed and no request field became required. Clients with strict enums or strict status-code handling should read the 202 items:
- Batch id look-ups (
filter[id]).GET /recipients,/customers,/ops/customers,/balancesand/platform/operatorsacceptfilter[id]=<id>,<id>,…(at most 100; above that400too_many_filter_values) and return only those rows; unknown or foreign ids are absent. Sendlimit≥ the number of ids. - Counts (
withTotal).GET /approvalsgainswithTotal(already served by/recipients, now declared);limit=1&withTotal=trueis the count-only form for badges. On every list,page.totalis computed on the first page only (a request withoutcursor). - Conditional GET (
ETag).GET /notifications,/notifications/unread-count,/approvalsand/documentsreturn a weakETag; send it back asIf-None-Matchwhen polling and the API answers304without a body while nothing changed. - Processing ETA.
Payment.processing(PaymentProcessing:statusqueued,position,etaSeconds,estimatedAt) is present while an approved, due payment waits in the operator's submission queue, and absent once submitted. - Approval-policy dual control.
ApprovalSubjectTypeaddsapproval_policy_change.PUT /customers/{customerId}/settings/approval-policies/{kind}answers202with the unchanged live policy andApprovalPolicy.pendingChangewhen the edit loosens control and another owner or admin exists; that person decides it through/approvals/{id}.Approval.subjectSummaryaddsrecipientMaskedIdentifier. - Batch-rail imports under four eyes (staff).
POST /ops/batch-rail/connections/{connectionId}/importsanswers202with aStaffApproval(batch_import) when four eyes apply (always for aproductionconnection);POST …/imports/{fileId}/statementreconciles the credits of a proposed import against the bank statement before it can be approved. - Operator offboarding under four eyes (platform).
POST /platform/operators/{operatorId}/offboardanswers202with anOperatorOffboardRequeston the first platform user's call; a different platform user's call within 24 hours offboards (200). - OAuth consent.
GET /auth/oauth2/authorizeno longer mints a code: with a web session it redirects to the web consent page, which confirms with the newPOST /auth/oauth2/authorize(OAuthConsentRequest→OAuthConsentResponse.redirectUrl). Mobile apps using the system-browser flow need no change beyond the one consent tap. - Also new.
GET /ready(readiness;503while the instance cannot serve,GET /healthstays liveness),POST /billing-runs/previews(billing dry run as a job,202+Job), six step-up actions andx-step-upon every platform write and on the remaining operator money and policy writes, the chain and roll-up fields ofAuditChainStatus, a 92-day window for free-text audit search (q),202fromPOST /me/email-changewhether or not the address is in use, and per-IP429s on anonymous routes and inbound provider webhooks.
1.0.0-draft.13 (2026-09-24)
All additive for integrators except the new step-ups on key revocation and webhook changes; staff endpoints need operator staff sessions unless an operator-key scope is listed:
- Developer portal and published contract (P9-T07).
GET /v1/openapi.json(tagpublic-api, no authentication) serves this contract as JSON in every environment withCache-Control: public, max-age=300, a strongETag(304onIf-None-Match) andX-Contract-Version. Swagger UI at/docsstays internal (DOCS_ENABLED); in production/docsredirects to https://developers.wirebloom.com/reference. A deprecated operation'sLink: <…>; rel="deprecation"points to https://developers.wirebloom.com/deprecations#{operationId}; deprecations can be declared in the contract (deprecated: truewithx-deprecated-atandx-sunset, optionalx-deprecation-link). Problem type URIs (https://api.banking.wirebloom.com/problems/{slug}) redirect tohttps://developers.wirebloom.com/errors#{slug}. - API usage and integration home (P9-T11). Customers:
GET /developer/api-usage(daily usage per key: requests, client and server errors, rate-limit hits, average duration, last use;from/toup to 90 days,apiKeyId,environment) andGET /developer/api-keys/{apiKeyId}/requests(the last 100 requests of a key over 7 days with a status breakdown; method, route template, status, duration and request id only, never bodies),api-keys.manage. Operator staff:GET /integration,GET /integration/api-usageandGET /integration/api-keys/{apiKeyId}/requests(integration.view, operator owners and admins; also operator-level keys withintegration:read): banking connections with health, breaker, webhook registration, backlog, reconciliation and checklist progress, key counts, usage across every key, integrator webhook health and portal links. A call appears within about 5 seconds. - Operator-level API keys and webhooks (P9-T08b, §2.1, §8.1, §8.2).
/api-keysand/integrator-webhooksarex-tenant: any;ApiKey.level;ApiScopeaddscustomers:read,customers:write,onboarding:read,treasury:read,reports:read,integration:read; the operator routes listed in §2.1 declarex-api-key-scopes.IntegratorEventTypeadds the six operator-only types;IntegratorEventaddscustomerIdanddata.related;data.objectaddscustomerandcompliance_hold. Step-ups:DELETE /api-keys/{id}needsapi_key.revoke; creating, updating, deleting and rotating the secret of an integrator webhook endpoint needintegrator_webhook.change(sessions only; API keys are not subject to step-up). - SDKs and Postman (P9-T08, §13). TypeScript and Python SDKs, generated C#, Java, PHP and Go clients, shared webhook test vectors and a Postman collection with environments, all versioned
1.0.0-draft.13. - Developer programme and simulations (P9-T09). Public sign-up for an operator's sandbox:
GET /developer/registration-options?operator=<slug>,POST /developer/registrations(always202) andPOST /developer/registrations/verify(201with the workspace and the firstwb_test_key).GET /developer/workspaceandGET /simulations(balances:read) plus the simulation operations under/simulations/*(sandbox keys only). Staff:/ops/developer-programme,/ops/developer-invitations,/ops/developer-registrations*(developers.manage) and/ops/simulations/provider-webhooks.Me.developerWorkspacetells a client the active customer is a sandbox workspace;BrandingPublic.sluggives the operator slug for the sign-up link. - Status page and support (P9-T10).
GET /public/statusand/public/status/subscriptions*(no authentication, double opt-in),GET /status(any member: the platform page and the operator's private page), staff/ops/status*(status.manage: incidents, updates, component overrides, subscribers). Support requests:POST /support/requests,GET /support/requests[/{id}](any member,self.profile) and the staff inbox/ops/support-requests*(support.manage). - VIBAN pools, partner assets and account identifiers (P10-T04, P10-T06). Customers:
GET /account-identifiers(the customer's VIBANs, including identifiers closing after a re-issue or provider switch) andGET /account-identifiers/{identifierId}/letter(PDF details letter),details.view. New customer-level eventbalance.details_changed: a balance's account identifier changed (data.status=reissue,provider_switchorclosing); fetchGET /account-identifiersfor the new details and tell your payers. Staff (operator.providers):/ops/viban-pools*,/ops/vibans/{vibanId}/{close,reissue,currencies},/ops/viban-detail-changes*andGET /ops/partner-assets(withfilter[expiringWithinDays]); new step-upsviban.pool_change,viban.lifecycleandpartner_assets.change. - Provider costs, packs and open banking (P10-T05, P10-T08). Staff:
/ops/provider-costs*(provider-costs.view/provider-costs.manage: costs, margin, imports, ingest, monthly close),/ops/resolution-packs*(resolution-packs.manage) and/ops/regulatory-packs*(regulatory-packs.view/regulatory-packs.generate); downloads need the step-upsresolution_pack.download/regulatory_pack.download. Customers:GET /connected-apps,GET /connected-apps/{appId}(open-banking.view) andPOST /connected-apps/{appId}/revoke(open-banking.manage), the third-party apps with open banking consent on the customer's accounts. - New capabilities.
integration.view,developers.manage,status.manage,support.manage,platform.status,provider-costs.view,provider-costs.manage,resolution-packs.manage,regulatory-packs.view,regulatory-packs.generate,open-banking.view,open-banking.manage(hyphenated names; clients match them as opaque strings).
1.0.0-draft.12 (2026-09-24)
All additive for integrators; the new staff endpoints need operator staff sessions:
- Documents requested inbox (customers).
GET /document-requests,GET /document-requests/{requestId}andPOST /document-requests/{requestId}/fulfil(tagactivity, capabilitiesdocument.view/document.upload) are the one inbox for every document the operator asks for, whether for a partner compliance case or enhanced due diligence.DocumentRequestcarrieskind,title(null for partner-case requests: show the kind),documentTypes,message,status(requested,fulfilled,cancelled),dueAt,customerNoteand the uploadeddocuments; never the case or its reason. Each request is announced by the genericdocument_requestednotification. Upload withPOST /documentsfirst, then fulfil with the document ids (422 document-not-cleanuntil the scan passed). The interim/compliance/document-requestsroutes of the P10-T02 drafts were never released and are removed. - Partner compliance cases (staff).
/ops/cases*(tagoperator-ops;cases.view,cases.respond,cases.approve): Banking Circle RFIs and inbound recall requests with their timeline, links, notes, documents, customer document requests, RFI answers, a four-eyes recall decision andPOST /ops/cases/sync. - Compliance-as-a-service (staff).
/ops/compliance/*(holds, queue, report, screening hits, recipient screening and rescreen, monitoring suppressions, gate settings, EDD cases and the review of documents customers provided),POST /ops/compliance/escalations,/ops/mlro/*(nominated officers, suspicion reports, DAML) and/platform/compliance/defaults(tagcompliance;compliance.view,compliance.manage,compliance.decide,mlro.decide). Payments held by the compliance gate stayon_holduntil staff release or block them. - Integrated Finance sync (staff).
GET /provider-connections/{connectionId}/sync,GET …/sync/links,POST …/sync/backfill,POST …/sync/driftandPOST …/sync/links/{linkId}/resolve(tagproviders,operator.providers). - New step-up actions.
cases.recall_decision,compliance.hold_decision,compliance.screening_decision,compliance.suppression,compliance.edd_decision,mlro.designation,mlro.sign_off; the sync backfill, drift and conflict resolution useprovider_connection.change. - New enum values.
PaymentExceptionKindaddscompliance_hold; reconciliation exception kinds addsync_conflict; staff approval kinds addcompliance_hold_release. Clients with a strict enum must accept them. - Tipping-off. Staff-written customer text (partner-case and EDD document requests) is checked by one shared guard and refused with
422error codetipping_off.
1.0.0-draft.11 (2026-09-24)contains breaking changes
- Customer types.
Customer.customerTypeisbusiness,sole_traderorindividual(POST /customerstakes it;identityTypeis derived:corporatefor businesses,individualotherwise). A legacy create withidentityType: individualbecomescustomerType: individualand itsregistrationNumberis dropped. Sole traders and individuals complete thepersonalsection ofKybCase(names, date of birth, nationality, residential address) instead of the company, address and ownership steps; an individual sends nocompanysection and a sole trader onlytradingName,incorporationCountry,industryCodeandwebsite(409otherwise). The verified identity (names, date of birth, nationality) cannot change once the identity check started (409 identity_locked). Clients that switch onidentityTypekeep working; clients that treat every customer as a company must handle the two new types. - Metadata. Payments, recipients, balances and customers carry
metadata: at most 20 keys ([A-Za-z0-9_-]{1,40}), string values of at most 500 characters, 8 KiB in total. List operations that support it take up to 5filter[metadata.<key>]=<value>parameters (ANDed). Metadata is integrator-owned and unverified: never base authorisation decisions on it. - Rails. New rail values
target2,ach,wireandeft, offered only when the operator's active connection reports them. Clients with a strictRailenum must accept the new values. - Purpose codes.
GET /payments/purpose-codeslists the catalogue per currency, destination and rail. Payments inCNHmust carry one ofGOD,STR,CTF,OTF(422 purpose_required/invalid_purpose). ElsewherepurposeCodeis optional and any ISO 20022ExternalPurpose1Code(4 letters) is accepted; a partner whose rail only takes a closed list drops a code outside it rather than failing the payment. Free text that is not a 4-letter code is refused (422 invalid_purpose). - Routing codes.
Recipient.bank.routingCodestakescnaps,bankCodeandbranchCode(with country requirement sets for CN and other markets inGET /recipients/requirements). - Bulk submit stays asynchronous (
202, draft.10).
Breaking changes for operator tooling (operator console and staff API keys only; integrator endpoints are unaffected):
ProviderConnection.statusis the lifecycleConnectionLifecycle(draft,configured,testing,active,draining,retired);disabledanderrorare gone (filter[status]=erroranswers400). Health ishealthy/lastHealth.PATCH /provider-connections/{connectionId}no longer takesstatus(422, the body is strict). Go live withPOST …/activate(activation checklist), stop new work withPOST …/drainand retire withPOST …/deactivate(step-upprovider_connection.change;409 connection-in-usewhile balances, settlement money, in-flight items or active mandates remain).POST …/testverifies but never activates.POST /provider-connectionsrefusescustomerId(422): an operator has one active banking connection per environment.- A live connection's config change may not remove what its activation checklist required (for example the Banking Circle
inboundIpAllowListin production) nor change Integrated Finance webhook keys (409); configured Integrated Finance keys may only add new key versions on sandbox connections (422 reserved_version/not_allowed). - New staff endpoints:
GET …/activation,…/webhooks(registration, keys, subscriptions, test),POST …/webhook-token/rotate, and/ops/treasury/*(operator treasury payments and FX under dual control, approval with step-uptreasury.approve).
1.0.0-draft.10 (2026-09-24)
POST /bulk-payments/{bulkPaymentId}/submit is asynchronous. It returns 202 with BulkPaymentSubmitAccepted (a Job plus the batch in submitting, header Location: /v1/jobs/{jobId}); poll GET /jobs/{jobId} for progress and GET /bulk-payments/{bulkPaymentId} for the final submitted / partially_submitted status and row results.
Platform
Notable changes to the platform as a whole (from the project changelog).
[Unreleased] — 2026-09-23 / 2026-09-24 (first commit 7ca6456 on main)
Added (99)
- 2026-09-28: Staff customer creation, owner invitations and per-currency customer breakdown (spec
superpowers/specs/2026-09-28-staff-customer-creation-and-currency-breakdown-design.md):POST /customersaccepts noprimaryOwnerfor console sessions (draft, no invitation, auditinvitationId: null; API keys still get422 /primaryOwner);POST/GET /ops/customers/{customerId}/owner-invitation(customer.create+people.invitestep-up;409 invalid-transitionwith an owner,409 conflictwhen pending withoutresend; resend revokes the previous link; token and code never returned or audited;tenancy.customer.owner_invited);POST /platform/operators/{operatorId}/customers(super admins,X-Access-Reason,platform.change, runs in the operator's tenant context;tenancy.platform_access+tenancy.customer.created);OpsCustomerSummary.primaryOwner;GET /ops/accounts/{currency}/customers(keyset on the aggregated total, search, status/type filters) andGET /ops/accounts/{currency}/summary(live,coverageDrift = settlement − booked). Web: Add customer on/ops/customersand on the platform operator page, Owner card on the customer People tab,/ops/accounts/[currency]with summary strip and CSV export (10,000-row cap), currency links on/ops/accounts. Contract additive on 1.0.0-draft.14 (SDK regenerated:CustomerCreate.primaryOwneroptional). Follow-ups N362–N368. Full gate:@wirebloom/db251/251 and@wirebloom/api1300/1304 (re-run standalone with--maxWorkers=2after hitting Postgresmax_locks_per_transactionunderpnpm check's full turbo parallelism; api's remaining 4 (activity-keyset.e2e.test.ts,activity.e2e.test.ts) are pre-existing timeouts in code untouched by this feature, reproducing in full isolation, most likely from this session's own leftover ephemeral test databases rather than a regression),web916/916,@wirebloom/providers727/731 (known pre-existing gap: missing Banking Circlecamt052/camt053fixtures, N-tracked separately);generate:check,sdk:checkandformat:checkclean. - 2026-09-28: Staff customer creation: final review fixes and deployment (P13-T02 merged to
main1d1132e, DigitalOcean deployment c7cd73e8 live onbank.wirebloom.com): the shared ops mutation hook now renews theIdempotency-Keyafter any stored 4xx other than 401/403/429, so a corrected resubmit no longer answers422 idempotency-key-reused(the three new customer dialogs use it; the remaining ops dialogs are tracked as N369); owner-invitation accept and staff resend are mutually exclusive (accept locks the customer row and re-reads the invitation status in the same transaction; both the revoke and the accepted update are predicated onstatus = 'pending'with row-count checks, resend answers409when the invitation changed meanwhile; a revoked link can no longer become the owner membership; race e2e added); the currency breakdown CSV export always walks pages by legal name so it reconciles with the summary strip (N364 notes it is not a point-in-time snapshot); the Owner card shows an error state on query failure and refetches after a409; the per-currency breakdown link on/ops/accountsis shown only withcustomer.view;GET /ops/accounts/{currency}/summarylists400in the contract. Gate: web 933/933, touched api suites 40/40, typecheck,generate:checkandsdk:checkclean. - 2026-09-28: Developer portal hosted on DigitalOcean (
developers.wirebloom.com, N252): second App Platform appwirebloom-developersfromplatform/infra/digitalocean/portal.yaml(oneportalservice built fromapps/portal/Dockerfile, no secrets, $5/month);tooling/deploy/do-app.shacceptsDO_APP_SPECandDO_APP_NAMEto drive it; the portal's API base URL ishttps://bank.wirebloom.com/v1(the code samples use the same host until a sandbox environment exists).DEPLOYMENT.md§8.9,ENVIRONMENT.md§7 andDEVELOPER_PORTAL.mdupdated; the owner sets thedevelopersCNAME at GoDaddy. - 2026-09-28: Customer registration and access approval (spec
superpowers/specs/2026-09-28-customer-registration-design.md, D-58):/registerfor businesses, sole traders and individuals;tenant.customers.access_statuswith auto or staff approval (platform.platform_settingsdefault, per-operatorregistration.approval),/ops/customers/registrationswith approve / reject / reverse (POST /customers/{id}/access-decisions, step-upops.kyb_decision),/pendingholding page and reduced capabilities,403 access-rejectedat login; onboarding modeprepare|liveper operator (KybCase.mode,409 onboarding-not-open); email verificationskippedbehind a super-admin setting until Resend is active; templatesregistration_received,access_approved,access_rejected,ops_registration_pending; migration 0056; contract additive on draft.14 (/ops/registrations,/platform/settings,BrandingPublic.registration,Me.access,Customer.accessStatus) - 2026-09-28:
KMS_LOCAL_ALLOW_PRODUCTION=true(owner opt-in, D-57 item 5) lets the local KMS backend run in production withMFA_MASTER_KEYSmandatory (packages/crypto,packages/auth, api identity config); the DigitalOcean app uses a software master key.packages/dbbootstrapCLI for the first operator and owner user (N348). First owner created on production;bank.wirebloom.comlive - 2026-09-28: DigitalOcean App Platform as primary hosting (D-57), AWS kept as the secondary option: app spec template
platform/infra/digitalocean/app.yaml, helperplatform/tooling/deploy/do-app.sh, workflow.github/workflows/deploy-digitalocean.yml; managed PostgreSQLwirebloom-pg(lon1), Spaceswirebloom-documents/wirebloom-archive, appwirebloom-bankcreated in project Wirebloom forbank.wirebloom.com. Code:@wirebloom/db/registertrusts a database CA fromDATABASE_CA_CERT(api, worker, migrate preload); storage accepts an S3-compatible endpoint in production behindSTORAGE_ALLOW_CUSTOM_ENDPOINT=truewith SSE-S3 (STORAGE_SSE). Docs: DEPLOYMENT §8, ENVIRONMENT §8, KNOWN_ISSUES N346–N352 - 2026-09-25: MASTER_PLAN "Outstanding work and next phase" section (development complete; next phase testing and launch); task Status cells normalised so the dashboard counts them (notes moved to the Task cell); HANDOFF checkpoint refreshed.
- Phase 11 / 12 review fix-forward (
docs/reviews/PHASE11_12_REVIEW.md§5 and §7, commit669cd97on top of0071977, 2026-09-25; full gate 118/118: api 1247, worker 485, db 238, web 848, mobile 370, providers 731, domain 647, portal 65, loadtest 32, mcp 33, crypto 38; contract 1.0.0-draft.14 unchanged in version,x-step-upregenerated additively; migration0055_p1112_review_fixes, journalwhen1791400000000): batch-rail import can no longer move a never-exported payment toprocessing/completedand the staff approval shows per-row effects (P1112-01); statements uploaded by someone other than the proposer, bound to the connection's settlement accounts, amount-less returns matched only when unambiguous (P1112-02); step-up coverage extended to customer limits, fees, pricing, billing, domains, branding, operators, provider-event replay and KYB decisions, with the 60-entry reviewed@NoStepUplist matched exactly bystep-up-coverage.test.ts(P1112-03, P1112-14); audit bridges recorded by chain order at partition bounds with strict verification and the epoch-0 tail check (P1112-04, P1112-12;audit.chain_anchors.run_prev_hash/bridge,audit.record_partition_anchors,audit.bridged,audit.legacy_anchored); fair per-chain verification budget withaudit.chain_verification_stale(P1112-05); default-partition moves keep dedupe keys (P1112-06); stale verified archives re-exported before a drop (platform.archive_current, P1112-07); archive bucket with Object Lock and delete denial (S3_BUCKET_ARCHIVE, P1112-08); operator-key fallback alert andKMS_OPERATOR_KEY_FALLBACKfail-closed switch, crypto-shredno_operator_keyalert (P1112-09); outbox claim skips saturated queues' topics without breaking aggregate order (P1112-10); session-settings start-up check and the proxySHOW/ epoch-0max(chain_seq)steps in DEPLOYMENT §4.14 (P1112-11, P1112-13); capacity-gate job failure ratio from pg-boss rows (P1112-29). Coord re-verification (§7): every Medium closed, 0 reopened, no test weakened; new P1112-62…-67 (2 Low, 4 Info) tracked as N324…N329 with the untracked Low follow-ups N330…N345. Verdicts: P11-T12 closed (Phase 11 complete, P11-T04 / P11-T05 now Met); P12-T01…P12-T07, P12-T09 Completed; P12-T08 / P12-T10 In Progress on the owner's staging capacity run (N323, Q-86) and staged-failure evidence (N316). Release candidate: no code blockers; operational checklist inRELEASE_READINESS.md§10. Next migrationwhen> 1791400000000. - Phase 11 / 12 residual wave (commit
0071977, 2026-09-25; full gate 118/118: api 1242, worker 482, db 233, web 848, mobile 370, portal 65, providers 727, domain 647, loadtest 31, mcp 33, crypto 35; contract 1.0.0-draft.14 additive, 529 paths, 664 operations, 856 schemas; migrations 0050–0054; Coord reviewreviews/PHASE11_12_REVIEW.mdrunning): security (P11-T01…P11-T11) approval-policy loosening under dual control with masked identifiers (0052), batch-rail imports under four eyes with statement reconciliation for credits and returns (0052), cross-operator session revocation and DSR pre-check parity, TLSverify-fullenforced in production with pgaudit andlog_parameter_max_length,capture_holdline validation, step-up on every/opsand/platformwrite (structural test), platform four-eyes on offboard (platform.operator_offboard_requests, 0054), staff rank guard, impersonation device revocation, CSP image origins and report throttling, redaction and placeholder-secret guards, anonymous and webhook IP buckets, OAuth consent page, email-change enumeration removed, supply-chain pinning, per-rule gitleaks, pnpm minimum release age, provenance and SBOM, envelope rewrap job, MCP per-client tokens with the read-onlywb_mcplogin (platform.mcp_clients, 0054); scale (P12-T01…P12-T09) per-operator audit chains with epoch-0 freeze and daily Merkle roll-up (0050, D-55),/v1/ready, per-job statement timeouts, stale-hold sweep, hot-queue partitioning, batched outbox pump and webhook ingestion, tenant fairness, API ceilings and processing ETA, notification and integrator fan-out batching, bulk submission sweeper, monthly range partitioning with a guarded copy-swap cut-over (0053, D-56), retention policy and 7-year Parquet archive with verified restore, read-replica and RDS Proxy routing, per-operator KMS keys with crypto-shredding, capacity gauges and alarms, trigram search indexes (0051), id look-ups,ETagon lists, web / mobile conditional polling, server pickers and bounded caches, capacity-test profiles with a COPY seeder and ascale-smokegate. Residuals KNOWN_ISSUES N308…N323; decisions D-54…D-56. - Phase 10 close-out review fix-forward (
docs/reviews/PHASE10_REVIEW.md§7, commitb07d896on top ofae627b9, 2026-09-24; full gate 118/118: api 1185, worker 411, db 171, web 833, mobile 364, portal 65, providers 724, domain 640, sdk 33, contracts 37; contract 1.0.0-draft.14, 526 paths, 660 operations, 849 schemas): P10R-01 customer holds view shows compliance-gate and recall-case holds only as a neutralpayment_reviewreservation (tipping-off); P10R-02 webhook registration routes, token rotation, connectiondeactivateand treasury exchange quotes run with no ambient transaction, the W1-11 exclusion becomes a lease (migration 0049, N193 resolved); P10R-03 provider-cost upserts take the cost-close lock and re-dated late lines leavepost_close; P10R-04 open-banking revoke intents cleared / bounded to 1 h and no retirement on a page-capped IF list (alert); P10R-05 per-ref isolation ofviban.details-sync, stuck order-intent alert, stale re-issue sweeper; P10R-06 one-click unsubscribe limited per token; P10R-07 step-up on sensitive operator settings and on the platform compliance floor (new capabilityplatform.compliance, access reason), service step-up checks refuse callers without a session; P10R-08 developer registration without the in-transaction better-auth sign-up mail; W3-13 concurrent vendor-page link answers 409. KNOWN_ISSUES N298…N307, RELEASE_READINESS §3 rows 26–27. - Phase 10 wave 3 (commit
95c6ded, 2026-09-24; full gate 114/114: api 1153, worker 388, db 164, web 830, mobile 363, portal 65, providers 719, domain 640, sdk 33; contract 1.0.0-draft.13, 525 paths, 659 operations, 849 schemas, redocly 0 errors; Coord review in progress): P9-T07 / P9-T11 developer portal appplatform/apps/portalgenerated from the contract (reference, guides, changelog, error catalogue,llms.txt, Markdown twins, publicopenapi.json, deprecation links; N85, N86 fixed;DEVELOPER_PORTAL.md) and the integration home with per-key request log and daily usage (migration 0046:iam.api_request_log,iam.api_key_usage_daily); P9-T08 / P9-T08b SDKs (TypeScript, Python; C#, Java, PHP, Go generated in CI from a hash manifest), webhook verification vectors, Postman collection and environments (SDKS.md), operator-level API keys and integrator webhooks with step-up (0042; P4 S-14 / Q-76 closed); P9-T09 / P9-T10 developer programme (invite or open registration, sandbox workspaces, abuse guard), 15 simulations incl. provider-backed, status page abstraction with Statuspage / Instatus adapters, incident comms, support requests (0043:platform.developer_*,platform.status_*,tenant.support_requests;SANDBOX.md,STATUS_PAGE.md,runbooks/INCIDENT_COMMS.md; N82 support half); P10-T04 / P10-T06 VIBAN pool lifecycle and orders, Banking Circle customer-details push (N58 part), account letters, partner-asset registry, IP-set change management, subscription and certificate alerts (0044; N163 fixed; INTEGRATIONS §12.3); P10-T05 / P10-T08 provider cost ingestion and monthly close, resolution packs, regulatory data packs (CSV / Parquet), IF open banking consents (0045;REGULATORY_PACKS.md,runbooks/BILLING_CLOSE.md). Wave 2 review fix-forward W2-01…W2-10, W2-12, W2-21, W2-27, W2-30, W2-53 (W2-48 partial; 0047 incoming hold guard and batched recipient screening). Direct-debitsignedAtdate bug fixed; capability naming convention (hyphens) with a seed / migration parity test; integrator eventbalance.details_changed. Documentation: MASTER_PLAN wave 3 rows In Review, KNOWN_ISSUES N220…N290 (wave 3 residuals and non-fixed W2 rows), OPEN_QUESTIONS Q-89, Q-90, RELEASE_READINESS §3 rows 23–25 and §7, DATABASE §17. - Phase 10 wave 2 (commit
74ce609, 2026-09-24; full gate 106/106: api 998, worker 338, db 148, web 759, mobile 360, providers 639, domain 640, kyc 34; contract 1.0.0-draft.12, 426 paths, 543 operations, 703 schemas, redocly 0 errors; Coord review in progress): P5-T09 Integrated Finance sync (migration 0039:providers.entity_links,providers.sync_status; list-basedif.backfill, event mirroring of IF-born entities, nightlyif.sync.driftwith IF-wins statuses, conflict resolution, sync report and console tab); P10-T01 Banking Circle cases (0040:compliance.cases,case_events,case_document_requests,case_documents; RFI and inbound recall,CaseEventsingestion plus polling, deadline reminders and escalation, four-eyes recall decisions, customer "Documents requested" on web and mobile); P10-T02 compliance-as-a-service (0041: counterparty screening provider in@wirebloom/kyc, pre-submission compliance gate with staff-only release and four-eyes threshold, monitoring rules withholdaction and suppressions, EDD cases, MLRO designations and suspicion reports under restricted RLS, Integrated Finance external compliance mode); runbookrunbooks/COMPLIANCE_OPERATIONS.md; webhook chain test; DECISIONS D-51. Residuals KNOWN_ISSUES N176…N192; non-fixed wave 1 review rows N193…N219. - Phase 10 wave 1 provider-platform parity (commit
d4cea6c, 2026-09-24; full gate 106/106: api 932, worker 305, db 129, web 736, mobile 355, providers 554, domain 616; contract 1.0.0-draft.11, 377 paths, 486 operations; Fable review pending): P5-T07 activation checklist, activate / drain / deactivate endpoints,providers.provisioning_holds, console Activation card,runbooks/PROVIDER_SWITCH.md(migrations 0035, 0038); P5-T08 webhook registration from the console (Banking Circle subscription lifecycle,clienttest, key and token rotation with grace windows, IF registration pack and auto-confirmation,providers.webhook_endpoints,providers.webhook_rejections, dashboard; migration 0037); P5-T10 async report client, returns, multi-currency VIBAN, customer-details push planner, rails /serviceLevels/ purpose-code catalogue, safeguarding mapping, UBO shape; P10-T03 individual and sole-trader customers,metadataattributes with filters, operator treasury payments and FX under four-eyes (payments.treasury_operations), railstarget2/ach/wire/eft, routing and purpose code catalogues, CNH (migration 0036). Env:BANKING_ENVIRONMENT,WEBHOOK_DR_BASE_URL,WEBHOOK_BC_MAX_AGE_HOURS,WEBHOOK_TOKEN_GRACE_HOURS,WEBHOOK_KEY_OVERLAP_HOURS,WEBHOOK_BC_FAILURE_EMAIL. Residuals KNOWN_ISSUES N160…N175. - Owner answers to Q-50…Q-88 recorded (2026-09-24; documentation only): OPEN_QUESTIONS rows marked answered with the differing answers noted; DECISIONS D-39…D-50 (BC contracting models, bidirectional IF sync, six SDKs, portal and registration toggle, per-operator status pages, compliance gate with WireBloom deciding holds, individuals in v1, cards and open banking consents, security, infrastructure, audit chains and keys, capacity) and D-32…D-36 Accepted; MASTER_PLAN row notes, new P10-T08 and P10-T09, P11-T05 decision, Phase 10 wave 1 (P5-T07, P5-T08, P5-T10, P10-T03) In Progress; PRD FR-INT-17, FR-PLAT-07, FR-PLAT-08, FR-ONB-07 in v1; INTEGRATIONS §10.6; COMPLIANCE §4.1 note; RELEASE_READINESS §3 row 18.
- Scalability audit 2026-09 recorded (documentation only;
reviews/SCALABILITY_AUDIT_2026-09.md: 11 High / 31 Medium / 8 Low):MASTER_PLAN.mdPhase 12 — Scalability and capacity (P12-T01…P12-T10; T01–T04 In Progress with the High fixes), KNOWN_ISSUES N117…N155, OPEN_QUESTIONS Q-77…Q-88, ARCHITECTURE §10.1 capacity targets and scaling model, LOAD_TEST §9 capacity-test plan, RELEASE_READINESS §3 rows 15–16 and §9. - Security audit 2026-09 recorded (documentation only;
reviews/SECURITY_AUDIT_2026-09.md: 0 Critical / 4 High / 8 Medium / 18 Low / 2 Info):MASTER_PLAN.mdPhase 11 — Security hardening (P11-T01…P11-T12; T01, T02, T03, T06 In Progress), KNOWN_ISSUES N94…N116 for the findings not being fixed now, OPEN_QUESTIONS Q-67…Q-76 for the owner decisions, SECURITY.md §9 and RELEASE_READINESS §3 rows 12–14 and §8 (go-live ordering: P11-T01/T02 before real money, P11-T03/T06 before the first AWS deploy). - Parity programme consolidated into the scope documents (D-31 positioning; documentation only): research
research/PARITY_INTEGRATED_FINANCE.md(IF parity 74 built / 19 partial / 7 missing),research/BANKING_CIRCLE_COVERAGE.md(BC coverage 34 / 20 / 23; recovered OpenAPI inresearch/banking-circle-oas/),research/PLATFORM_PARITY_SCOPE.md(SC-01…SC-61); MASTER_PLAN tasks P5-T07…P5-T11, P9-T07…P9-T11 (with P9-T08b) and new Phase 10 P10-T01…P10-T07 (P3-T15 and P5-T04 annotated); PRD FR-INT-09…16, FR-PLAT-05/06, FR-OPS-10/11, FR-ONB-07, FR-PAY-13, FR-REP-05 and a positioning note; INTEGRATIONS §10–§12 and §7 (BC answers from the OpenAPI, BC-24…BC-32, IF-25…IF-36); decisions D-32…D-36; questions Q-53…Q-66 (owner questions O-1…O-10 merged); known issues N85…N93; ARCHITECTURE §6 provider model; RELEASE_READINESS §7. - P6-T06 frontend review fixes (PHASE6_REVIEW_FRONTEND.md F-01…F-14, N81, S-05) and web draft.9 adoption: one
safeReturnTo(apps/web/src/lib/url/return-to.ts: parses against a fixed origin, refuses control characters, backslashes,//, absolute URLs, auth paths and/api/) for the login machine, recipient wizard and every wizard close target (tab-bypass open redirect closed); nonce-based Content-Security-Policy per request frommiddleware.ts('strict-dynamic', Sumsub only on/onboarding/*, Sentry ingest inconnect-src,object-src 'none',frame-ancestors 'none',CSP_MODE=enforce|report-only,/api/csp-reportcounting stub) and HSTS in production builds (SECURITY.md §4.1); N81 root-caused in the browser and fixed (Suspense around the (app)/(auth) layoutchildren, theme bootstrap moved to<body>with the nonce,hydrationcontext on Sentry #418 events), known-issue entry removed after nine concurrent clean a11y sweeps; ops e2e asserts step-up positively and negatively (first release asks, cancel leaves the payment held, second action in the window does not ask,holdnever asks); console guard also covers contexts a test creates (a11y phone contexts, checker contexts) and names the page of a page error; step-up prompts queue (F-04);GET /me429 shows a rate-limit page with the wait and request id (F-05); one-time secrets reset from the mutation cache (F-06); fresh-key step-up retry removed (F-10); BFF turns upstream 3xx into 502 (F-11); floating feedback button desktop-only (F-12); branding host validated (WEB_BRANDING_HOSTS, F-13); mobile: production release check fails on empty certificate pins (F-08), KYC WebView refusesdata:(F-09), recovery codes no longer shared as text (F-14); web on contract draft.9 (feedback endpoint, zod swap removed, staff directory, accounting providers, run-nowrunId, servercanDecide, session-end reason on the login page). - Backend loose-ends pass (KNOWN_ISSUES N65, N79, N82, N62, N64, N59): contract 1.0.0-draft.9 (356 paths, 465 operations, 582 schemas; was draft.8 351 / 459 / 570); migration 0033 (
tenant.feedback,warehouse.api_request_counts, dropspayments.exchanges.confirmation_job_id/confirmation_document_id). Session look-ups served from the request cache withwb_cacheinvalidation (revoked sessions refused at once);401 session-expiredreason(idle/revoked/expired); product feedbackPOST /support/feedbackand staff triage/ops/feedback(feedback.manage, 10 per hour per user);GET /ops/staff-directory(reports.view);KybCaseDetail.canDecide,PaymentException.canDecide; run now returns202 { runId }and runs within seconds (reports.run);?source=warehousewithdataAsOfon the three fact-backed reports; XLSX / PDF-summary report exports through the worker (reports.export); request metering intofact_usage.api_calls(API_METER_FLUSH_MS); accountingGET /integrations/accounting/providers, sync-log description / counterparty, comma-list status filter;@wirebloom/contracts/clientwithout zod (headers.ts); alertswarehouse.driftandwarehouse.stalewith runbooks. - Compliance controls pass (COMPLIANCE.md §7, KNOWN_ISSUES N66–N70, N72, N73, N76–N78): migration 0032 (
iam.terms_acceptances,tenant.dsr_requests,tenant.complaints,tenant.staff_approvals,tenant.compliance_reviews,ledger.safeguarding_reconciliations; customer retention / review / screening dates; company persons with ownership chains, control by other means, PEP declaration and source of wealth;providers.events.payload_purged_at) and contract 1.0.0-draft.8 (351 paths, 459 operations, 570 schemas). Neutral default statement and email footer with the operator's approved wording fromsettings.compliance.regulatoryFooter;GET/PUT /ops/compliance/settingsholds every decision-dependent threshold with safe defaults; KYB approval requires completed KYC of every person and always records a risk rating; four-eyes (security.fourEyes) for KYB decisions, limit-exception and recipient approvals (/ops/four-eyes); staff closure decisions start the retention clock (7 y customer data, 5 y KYB documents); data-subject requests with 30-day deadlines, JSON + PDF data-map export and scheduled pseudonymisation; complaints (customer and staff routes, deadlines, notifications); terms acceptance recorded with a re-prompt and a setting-gatedterms-outdatedrefusal of money movement;POST /audit-events/exports,GET /ops/audit/chain-status, audited report reads; worker jobscompliance.safeguarding-reconciliation(shortfall alert),compliance.screening-refresh(risk-based),compliance.periodic-review,retention.provider-requests,retention.provider-events,retention.customer-data(dry run until enabled); security anomaly alerts (MassDataExport, RepeatedDeniedActions, OutOfHoursRoleChange) anddocs/runbooks/BREACH.md. - Cards module (P4-T13, FR-CARD-01/02, flag
cards):CardIssuingProviderin@wirebloom/providers(src/cards: cardholders, virtual / physical cards, get / list, freeze / unfreeze / activate / terminate / replace / relink, controls, processor-hosted secure sessions for PAN and PIN, 3DS decisions, card transaction listing, neutral card events) with the Integrated Finance / Thredd adapter (recorded-style fixtures, inferred shapes flagged, never run against IF) and a deterministic sandbox issuer (simulated authorisations, settlements, reversals, refunds, 3DS challenges; the sandbox now reports thecardscapability); the IF webhook parser addsdata.cardEventfor thecards,card-transactionsandcard-transaction-authenticationsmodules. APImodules/cards:/cardsCRUD and lifecycle (members limited to their own cards, ETag / If-Match, limits sent to the processor),/cards/{id}/details|pinsecure sessions (holder only, step-up, no card data),/cards/{id}/activate|replace|terminate(terminate and replace now need step-upmfa.change),/cards/three-ds-challengeslist / get / decision,/cards/{id}/transactions, operator/ops/cardslist, transactions, compliance freeze / unfreeze;CardEventsWebhookHandler(binding pending inProvidersCoreModule). Workercards.apply-event(authorisation hold, settlement capture tocard_collectionwithcard_fx/card_atmfees, reversal, refund, 3DS challenge, status, wallet tokens),cards.sync,cards.3ds-timeout,cards.compliance-freeze. Migration 0031 (cardholders, card authentications, card and card-transaction columns, overdraft of card settlements from service contexts, pending card activity in the balance currency, compliance-hold trigger). Notificationscard_status,card_transaction,card_3ds_challenge. Contract:Card(last4/expirynullable,frozenBy,statusReason,replacesCardId,controlsEnforcement,wallets),CardSecureSession(purpose,kind,token,sdk;urlnullable),CardTransactionextensions,CardReplace,CardTerminate,CardOpsAction,ThreeDsChallenge; new operationsactivateCard,replaceCard,listThreeDsChallenges,getThreeDsChallenge,listOpsCards,listOpsCardTransactions,freezeOpsCard,unfreezeOpsCard. INTEGRATIONS §4.2 "Cards (Thredd)" and IF-20…IF-24. - Compliance requirements (P2-T07): new
docs/COMPLIANCE.md(regulatory model options for Q-26 mapped to the ledger'sprovider_settlement/suspense/operator_opsaccounts and the Banking Circle / Integrated Finance models; KYB data set against MLR 2017; UK GDPR roles, lawful bases, data map, retention reconciled with DATABASE.md §13, data-subject request design, processors, transfers, DPIA outline, 72-hour breach runbook; screening and monitoring policy; audit evidence and partner due-diligence checklist; complaints and T&C placeholders; gap register G-01…G-25).SECURITY.md§7 now summarises and links it;OPEN_QUESTIONS.mdadds Q-38…Q-49. Documentation only; no code changed. - Performance tuning pass (KNOWN_ISSUES N61, LOAD_TEST.md §6.4): migration 0030 adds
ledger.journal_lines.posted_at(entry posting time, trigger + back-fill) and keyset indexes for every activity source, splitsledger.customer_transactionsinto six source views (same columns), and addsledger.customer_transactions_page(keyset +LIMITinside every source; activity first page at 100k transactions 964 ms → 1 ms),ledger.customer_transactions_count,ledger.customer_activity_matches,pg_notifytriggers for the outbox (wb_outbox) and for cache invalidation (wb_cache), andproviders.events.processing_note. API:GET /transactionsreads through the page function (cursor carries microseconds; contract unchanged), per-process request caches for tenant access / capabilities / operator settings with LISTEN-based invalidation (API_CACHE_TTL_MS),session.*rate limits in memory (RATE_LIMIT_SESSION_IN_MEMORY),DB_POOL_MAX, provider events no handler takes closed asignored. Worker: per-queue concurrency / batch size for the hot payment-path queues (0.5 s poll, burst on full batches;WORKER_CONCURRENCY,WORKER_BATCH_SIZE,JOB_FAST_POLLING_INTERVAL_SECONDS), dedicated money pool (DB_MONEY_POOL_MAX),PGBOSS_POOL_MAX, queue groups@money/@background, continuous outbox pump (OUTBOX_PUMP_ENABLED,OUTBOX_PUMP_INTERVAL_MS; commit→dispatch p95 50.8 s → 37 ms). Local load profile PASS with every queued job drained in the window. - Staff mobile approvals, API side (P9-T03) and the scheduled-reports API (P9-T04 §10): contract 1.0.0-draft.7 (318 paths, 422 operations, 537 schemas). Staff step-up actions
ops.payment_action(every staff payment action but the protectivehold),ops.kyb_decision,ops.recipient_decision(operator-mode approve / decline; customer mode keepsrecipient.create),ops.exception_resolveandops.alert_resolve, declared (x-step-up) and enforced server-side, bound to the action, 5 minutes;Idempotency-Keyrequired onPOST /exceptions/{id}/resolve, optional on the recipient, KYB and alert decisions;OpsPayment.allowedActionsfrom the payment machine and the caller's capabilities;canDecideon KYB review items, limit exceptions, monitoring alerts and operator-modeRecipient.approval;withTotalon/kyb/review-queue,/exceptions,/ops/monitoring-alerts,/ops/recipients;GET /ops/recipients/{id},GET /ops/customers/{id}(standing, balances per currency, payments in 30 days, open issues),GET /ops/payments/{id}/provider-events(payments.ops, no payloads). Staff push: notification categoryoperations(migration 0029, Android channeloperations), templatesops_payment_attention,ops_kyb_submitted,ops_recipient_review,ops_exception_opened,ops_alert_opened(audience: 'staff', operator tenant, item ids,categoryId: 'approval') produced where payment exceptions, KYB submissions, operator-mode recipient reviews, limit exceptions and monitoring alerts open, to staff whose role holds the deciding capability. Staff idle timeout (30 min) enforced on mobile bearer requests and refresh (session and refresh tokens revoked); fixed the staff check behind the idle rule, which counted every user as staff once any staff membership existed (customers on the web got 30 instead of 60 minutes)./ops/report-schedulesCRUD, run-now and run history onwarehouse.report_schedules/report_runs(new capabilityreports.schedulefor Op Owner / Admin / Finance). Platform console gaps (P6-T03):GET /platform/operators/{id}/usage(months or days) andGET /platform/usagefromwarehouse.fact_usage,GET /platform/health(worker heartbeats, job runs, outbox backlog, connections with breaker state, error rate and last reconciliation, webhook backlog, balance drifts),GET /platform/provider-catalogue(every adapter with form schemas, catalogue versions and capability matrix) with versionPOST/GET/PUT(ETag),GET /platform/audit-events(reason required, audited),Me.platformCapabilities,X-Access-Reasondeclared on/audit-eventsand/ops/dashboards/{dashboard}, plan search,Plan.operatorsandDELETE /platform/plans/{id}(refused while assigned);super_adminseeded withreports.viewandaudit.view. E2e:staff-approvals(11),staff-session(4),staff-report-schedules(3),platform-console(6). - Accounting integrations (P9-T02, FR-INT-08): new
@wirebloom/accountingwith the provider interface and Xero / QuickBooks Online adapters (OAuth 2.0 authorization code + PKCE, signed session-bound single-use state, KMS-enveloped tokens with refresh single-flight across processes, organisation/realm selection, chart of accounts, contact upsert, bank transactions / Purchase / Deposit withWB-markers,Idempotency-Key/requestidand marker lookup after unknown outcomes, per-organisation rate budgets and429handling), guarded HTTPS transport, recorded fixtures, scripted transport and provider simulators; API/v1/integrations/accounting(connect with step-upaccounting_connection.change, callback, organisation selection, mappings validated against the chart, sync now, sync log, chart of accounts for the annotation category picker;customer.settings, sessions only); workeraccounting.sync/accounting.sync-due/accounting.refresh-tokenswith leases, keyset cursor with a settle window, per-leg backoff and dead-lettering; migration 0027 (tenant.accounting_connections,accounting_mappings,accounting_sync_log, RLS customer, posting trigger for automatic mode); contract additions (6 paths, 9 operations, 20 schemas, StepUpAction valueaccounting_connection.change); INTEGRATIONS.md §9 andrunbooks/ACCOUNTING_INTEGRATIONS.md. Not yet run against real Xero/QuickBooks developer accounts (INTEGRATIONS.md §9.7). - Reporting warehouse, scheduled reports and MCP operational tools (P9-T04, RULES §15/§51): migration 0028 adds schema
warehouse(staff RLS; reference dims readable, watermarks service-only) withdim_date/currency/rail/operator/customer/provider,fact_transactions(per journal line),fact_payments(lifecycle timings, SLA),fact_fees,fact_onboarding,fact_provider_calls,fact_usage(+ per currency),watermarks,rechecks,report_schedules,report_runs; new@wirebloom/warehouse(incremental idempotent loaders with UUIDv7 /updated_atkeysets and a 15-minute overlap, nightly facts-vs-ledger re-check with backfill, retention, the operator report catalogue with the API's OLTP SQL plus warehouse-backedfee-income/provider-settlement/onboarding-funnel, schedule periods and cron validation, dependency-free PDF summary); worker jobswarehouse.refresh(10 min),warehouse.recheck(03:15, critical alertwarehouse.drift) andreports.scheduled(5 min: CSV / XLSX / PDF document,report_readyto staff withreports.view, auditreport.scheduled_generated); notification templatereport_ready; new app@wirebloom/mcp(stdio and stateless streamable HTTP with a static bearer token, loopback by default, distroless Dockerfile): eight read-only tools (platform.health,operator.summary,customer.lookup,payment.trace,reconciliation.status,queue.status,report.run,audit.search) with a mandatory auditedreason(mcp.tool_call), read-only transactions, PII masking and row / byte limits. Docs: WAREHOUSE.md (model, refresh, metric definitions, API proposal), MCP_TOOLS.md. - P6-T01 API mismatches: contract 1.0.0-draft.6 (302 paths, 399 operations, 502 schemas):
GET /ops/journalitems withlines; idempotency releases the key on 401/403/429 (retry after step-up with the same key succeeds); typedTransactionExportFilter;GET /documentsstatus/date/search filters; scheduled paymentswithTotalandtemplate.recipientName;Recipient.approvalwithcanDecide,Approval.received,GET /payments/{id}/approvals, primary-owner transfer list/get;Team.updatedAt/IntegratorWebhook.updatedAt; defaulted fields optional in the generated client types (defaultNonNullable: false);Railbacsend to end with migration 0026 (ALTER TYPE platform.rail ADD VALUE IF NOT EXISTS 'bacs');GET /me429 test; Expo pushes carry the AndroidchannelIdper category andcategoryId: 'approval'on approval requests; ENVIRONMENT.md rows forOAUTH_MOBILE_REDIRECT_URIS(https/auth/callbackin staging/production) andMOBILE_MINIMUM_APP_VERSION. - API gaps for the operator console, customer screens and mobile (P6-T06 preparation): contract 1.0.0-draft.4 (300 paths, 396 operations, 500 schemas) with typed report rows, dashboard widgets, provider connection config/credentials (JSON Schema generated from the adapters' zod), monitoring params, notification data and WebAuthn options; staff reads of balances, payment events and approvals across the operator;
/ops/customers, the customer communication log,/ops/staffand custom staff roles; operatorGET /provider-catalogue; fee catalogue item GET and customer-readable fee charges; display names on exception queues and KYB; mobile device binding (deviceId,expiresIn),refresh-token-reused, RFC 7009 revocation andHealth.minimumAppVersion;GET /notifications/{id},Device.current, exchange confirmation as PDF,webhook.test; e2e suitesmoney-gaps,ops-gaps,identity-gaps,notifications-gaps. No migration. - Partner adapters wired into the platform (P5-T06): API and worker register Banking Circle with a database VIBAN pool (
providers.viban_pool/viban_orders,SELECT … FOR UPDATE SKIP LOCKED, per-holder advisory lock) and the batch rail with a database batch store (providers.batch_files/batch_rows; late appends move to the next batch, rendered payments cannot be cancelled), both in@wirebloom/dbstores; webhook receiver setsx-wirebloom-source-ipfrom the trusted client address (client values stripped) and accepts Banking Circle'sapplication/octet-streambodies; onboarding sends Integrated Finance the registered address, relations, registration and risk, pushes Banking Circle Pobo/Cobo VIBAN customer details, opens provider accounts per routed currency (customer_provider_refs.accounts,ledger.provider_accountswith the IF account model) and ledger provisioning links the balances; worker mapsproviderStatusthrough the partner tables and raises the new payment exceptionprovider_attention(also for rolled IF conversions), pollsexceptionpayments (M-09) and matches direct debits on our end-to-end id (M-02); Integrated FinancerecoverWebhooks; HTTP client text/XML bodies and safe redirects; neutralproviderStatus/attention/sourcefields; batch rail console/v1/ops/batch-rail/*(status, files, export, import with step-upbatch_rail.import);POST /provider-connections/{id}/test{"dryRun": true}; contract 1.0.0-draft.5 (299 paths, 395 operations); migration 0024; INTEGRATIONS.md v2 final (§4.4 wiring, §7 consolidated partner questions BC/IF/BR, §8 go-live checklists), runbooks completed (BANKING_CIRCLE.md,INTEGRATED_FINANCE.md, newBATCH_RAIL.md), DATABASE.md 0023/0024, OPEN_QUESTIONS Q-25 status and Q-31…Q-33; tests: API e2eproviders-adapters(9) andbatch-rail(3), worker integration (onboarding accounts, attention, M-09 poll, DD end-to-end id, FX roll), unit (source IP,mappingOf, HTTP client redirects/text, IF recovery). - Phase 4 consolidation (P4-T15): cross-currency payments wired end to end (
PaymentsServicebinds the exchange, routes submission throughpayment.exchange_required, releases on cancel/reject, dry-run FX fields; e2e create → exchange → submit with the worker engines in-process; closes N49); webhook chain Sumsub → Resend → Exchange → DirectDebit → PaymentEvents → queue;PaymentsModuleexportsOpsPaymentsServiceandTransfersService; payments, bulk batches and recipients open approvals throughApprovalsService.open(approvals-core.module.ts), worker-created approvals fill the 0017 columns, payment views countapproval_decisions; customer roles gainreports.export(all) andaudit.view(owners/admins); recipientsapprovalModefallbackoperator; nine notification templates (exchange_status,scheduled_payment_failed,scheduled_payment_inactive,mandate_status,collection_status,collection_pre_notification,fee_funds_required,recipient_verification,webhook_paused) with the reusing call sites switched; contract 1.0.0-draft.3 (289 paths, 379 operations) with the whole P4 backlog, no hidden routes left,not-implemented(501) mapped from adapters;@wirebloom/integrations-webhooks(N50 guard/signing/transport); storage XLSX; telemetry hook timeout 60 s; DATABASE.md 0011–0022, worker job catalogue, outbox topic table. Money review fixes: no payment without a hold is ever sent and hold-less captures/returns raiseprovider_conflict(M-01), scheduled cross-currency payments converted on their date with a partner re-quote (M-04), direct-debit polling matches only the collection's own partner reference and never re-credits a consumed transaction (M-02), in-flight conversions cannot be cancelled and a late partner completion is booked (M-03),ledger.integritychecks subject invariants (M-07); tenancy review: drawdown events matched on the event's operator and connection (T-02), tenant jobs scoped to the envelope operator (T-03). - Phase 3 consolidation (P3-T16): contract 1.0.0-draft.2 (248 paths, 332 operations) with the P3-T05/T06/T12/T13/T14 backlog:
GET /documents,POST /documentsJSON upload intent +DocumentWithUpload,POST /documents/{id}/complete,Document.status, notification Web Push key/test-send/unsubscribe routes,emailDigest,POST /me/email-change/confirm,Me.impersonation.id,LoginResult.passkeyOptions, optionalIf-Matchfor items without a GET, capability rules (primary-owner confirmself.profile,customer.decide, staff invitationsstaff.manage), problem typedomain-not-approved; API serves them (no hidden routes). Resend delivery webhooks applied throughWEBHOOK_DISPATCHER; branded identity emails viacreateEmailSender; MFA secrets on@wirebloom/cryptowith KMS and asecrets.rotate-mfajob;identity.purge-expiredjob;wb_pgbossrole/schema and weak-password refusal in the migrate task; RDS CA bundle and telemetry preload in the api/worker images; auth/provider/breaker/webhook metrics, Sentry capture of 5xx, webwithSentryConfig; shared vitest presets everywhere and measured coverage floors; e2e smoke signs in. P4-T04/P4-T05 follow-ups: contract adds operator domains (6 routes), public logo, customer standing, settings export, plan/flag GETs, branding/settings fields, customer-mode recipient approve/reject,RecipientRequirements.alternatives,approvalMode: nonewith verification settings (contract now 257 paths, 345 operations); login step 1 returns operator branding;emailFromNamein the From header; recipient-specific notification templates;@wirebloom/db/domains(domain verifier, alert triggers) andseedOperatorBilling(used by operator provisioning); worker jobstenancy.domains.verifyandbalances.watch-low(stub). - Technical audit of the legacy portal (
review/WireBloom_Portal_Technical_Audit_2026-09-23.pdf) and requirements-compliance presentation. - Documentation set v2: SCOPE_OF_WORK, PRD, ARCHITECTURE, DESIGN_SYSTEM, DECISIONS (D-00…D-27), OPEN_QUESTIONS, MASTER_PLAN, HANDOFF, DATABASE, SECURITY, TESTING, DEPLOYMENT, README, PROJECT_PLAN.html generator.
- Research: Equals Money product and UX review; Integrated Finance API review; Banking Circle Connect API review;
INTEGRATIONS.md(provider interface mapping, capability matrix, per-tenant configuration, partner questions); brand assets. - OpenAPI 3.1 contract
docs/api/openapi.yaml(243 paths, 325 operations, 357 schemas;/public/currencies, Health with checks, generic 405/409/415 problem types) anddocs/api/API.md; generator underdocs/_tools/openapi-gen/. - DATABASE.md: tables for limits and exceptions, integrator webhooks and deliveries, manual postings, customer notes, low-balance alerts, closure requests, jobs, API idempotency keys; funds requests gain a source account.
- PRD Appendix A: read capabilities, annotations, onboarding, impersonation, limits, reconciliation, webhooks and the platform.* split.
- Frontend review fixes (P6-T06): shared
safeReturnTo(open-redirect variant closed), Content-Security-Policy with per-request nonces andstrict-dynamicplus HSTS and a report endpoint (S-05 resolved), e2e step-up assertions replacing the optional seam, hydration issue N81 root-caused (page segment streamed into a Suspense-less<main>) and fixed with layout Suspense boundaries (9/9 concurrent sweeps clean), queued step-up prompts, rate-limited page forGET /me429, one-time secrets cleared from the cache, BFF 3xx handling, branding host allow-list, mobile release-check pin guard and WebViewdata:refusal; draft.9 adopted in web; 688 web tests, e2e 60 passing with 0 known-issue annotations. - Coord: final full gate 106/106 (2026-09-24), prettier clean, schema no diff, workflows lint clean.
- Mobile draft.9 adoption: session-end reasons (idle/revoked/expired with refresh-and-retry on expired),
KybCaseDetail.canDecide, payment-exception queue kind with deep links and resolutions, feedback sheet under More; 340 mobile tests. - Backend loose-ends pass: session cache wired with trigger invalidation (N65), feedback API (
POST /support/feedback, ops triage,feedback.manage),canDecideon KYB detail and payment exceptions, staff directory for pickers, run-now returns a run id via areports.runjob, accounting providers list and log fields,401 session-expiredreason, zod-free contracts client entry, warehouse-backed report source withdataAsOf, XLSX/PDF report exports as jobs, API request metering intofact_usage,warehouse.stalealert, exchange confirmation columns dropped; contract 1.0.0-draft.9 (356 paths, 465 operations); migration 0033; full gate 106/106 (api 863 tests). - Accessibility and performance pass (P6-T05) with the remaining web screens: focus return and scroll-region fixes in
@wirebloom/ui, 44 px touch targets at coarse pointers, sign-in focus management, phone sweep of 70 routes (0 axe violations, 0 horizontal scroll),docs/ACCESSIBILITY.md; Lighthouse CI config and route bundle budgets (Home first-load JS 510 → 308 kB gz, desktop LCP 977 → 838 ms), lazy palette/WebAuthn/drawers, zod kept out of the browser,docs/PERFORMANCE_WEB.md; accounting integration settings and callback, annotation category picker; scheduled reports page andreport_readydeep link; platform usage screens; feedback widget and help centre (15 articles); four-eyes page and202 StaffApprovalhandling; 632 web tests, e2e 49 passing. - Coord: full monorepo gate 106/106 (2026-09-24); CI gains the bundle-budget step and a gated Lighthouse job; migration journal renumbered by timestamp.
- Compliance controls pass (N66–N78): operator compliance settings (regulatory footer/model, KYB verification and risk defaults, cadences, retention, terms, four-eyes), daily safeguarding reconciliation with shortfall alerts and sign-off, KYB approval requiring completed person KYC and a risk rating, company-kind persons with ownership chains and PEP/source-of-wealth fields, risk-based re-screening and periodic reviews, closure decisions setting the retention clock, retention purges (provider requests/events, customer data pseudonymisation in dry-run), data-subject requests with export/erasure jobs, complaints with SLA dates, four-eyes staff approvals with maker≠checker, terms acceptance records and re-prompt, audit-event export and chain status, breach runbook and three anomaly alerts; migration 0032; contract 1.0.0-draft.8 (351 paths, 459 operations); 19 e2e + worker integration tests.
- Cards module (P4-T13, flag
cards):CardIssuingProviderwith an Integrated Finance/Thredd adapter (35 fixtures, scripted transport) and a deterministic sandbox, cards lifecycle (create/activate/freeze/unfreeze/terminate/replace), controls, processor-hosted secure sessions for PIN/PAN, 3DS challenges and decisions, card transactions with authorisation holds, settlement capture tocard_collection, FX/ATM fees, refunds, operator oversight and freeze-on-hold; workercards.sync/cards.3ds-timeout; card webhook handler bound into the dispatcher chain; migration 0031 (cardholders,card_authentications, card columns,post_entryoverdraft rule for card presentments); 16 e2e + 9 worker tests; INTEGRATIONS cards subsection with IF-20…IF-24. - Mobile draft.7 adoption: staff decisions on the real
ops.*step-up actions withallowedActions/canDecide, single-call staff reads,withTotalbadges, staff push andreport_readydocument screen, cross-tenant notification taps via account switch,deviceId/expiresIn/refresh-token-reused/revoke handling, recipient and payment approval views, current-device marking; 312 mobile tests. - Performance pass (N61): activity read model split into six keyset-paged source views with
customer_transactions_page,journal_lines.posted_atand keyset indexes (first page 964 ms → 1 ms at 100k), outbox LISTEN/NOTIFY pump (commit→dispatch p95 51 s → 37 ms), hot-queue concurrency/batching with dedicated money pools, per-request TTL caches with trigger-driven invalidation, in-memory session rate-limit buckets,DB_POOL_MAX/DB_MONEY_POOL_MAX, unhandled provider events closed asignored; migration 0030; before/after in LOAD_TEST §6.4. - Staff API pass (P9-T03/P9-T04/P6-T03 API side): contract 1.0.0-draft.7 (318 paths, 422 operations, 537 schemas): staff step-up actions enforced on decision routes, idempotency on exception resolution, staff reads (
/ops/customers/{id},/ops/recipients/{id}, per-payment provider events),allowedActions/canDecide/withTotalon queues,operationspush category with fiveops_*staff templates wired to producers (migration 0029), 30-minute idle rule for staff bearer sessions (and a fix that gave customers the staff timeout),/ops/report-scheduleswith capabilityreports.schedule, platform health/usage/audit/provider catalogue versions/plan delete,Me.platformCapabilities; 809 api tests. - Platform console and web leftovers (P6-T03): platform operators/plans/flags/providers/health/audit screens with an access-reason dialog, customer onboarding wizard with hardened Sumsub WebSDK embedding and sandbox test panel, direct-debit mandate wizard and detail, batch-rail ops screen, approvals oversight on
GET /approvals, translatable@wirebloom/uilabels viaUiLabelsProvider, app-link association routes for mobile; 543 web tests, 36 e2e flows green; contract draft.6 fallout fixed. - Accounting integrations (P9-T02):
@wirebloom/accountingwith Xero and QuickBooks Online adapters (OAuth2 + PKCE, signed one-time state bound to session/customer, KMS-enveloped tokens with cross-process single-flight refresh, contacts upsert, bank transactions/purchases with deterministic idempotency markers, rate-limit pauses, revoke), API/integrations/accounting/*with step-up, worker sync engine over journal legs with retries/dead-letter and an automatic mode driven by a journal trigger; migration 0027; 62 tests; INTEGRATIONS §9 anddocs/runbooks/ACCOUNTING_INTEGRATIONS.md. - Reporting warehouse and MCP tools (P9-T04):
warehouseschema (date/currency/rail/operator/customer/provider dimensions; transaction, payment lifecycle, fee, onboarding, provider-call and usage facts) refreshed incrementally every 10 minutes with watermarks and a nightly recheck against the journal (warehouse.driftalert), scheduled reports (report_schedules/report_runs, CSV/XLSX/PDF summary,report_readynotification), warehouse-backed fee-income/provider-settlement/onboarding-funnel with OLTP parity tests;apps/mcpread-only MCP server (8 tools, mandatory audited reason, masking, limits, stdio + localhost streamable HTTP with bearer token); migration 0028;docs/WAREHOUSE.md,docs/MCP_TOOLS.md. - Load test and drills (P8-T02 prep):
@wirebloom/loadtestk6 scenarios (login/TOTP, reads with cursors, payment create with idempotency, approvals with step-up, signed webhook bursts, API keys, rate-limit probe, quotes) with NFR thresholds, seeding, DB probes and Markdown reports; local 90 s run passed (62.8 req/s, 0 errors, trial balance 0 after load); restore drill script with local PASS (RTO 11 s on a 207k-line ledger) and the AWS PITR procedure; failover runbook; manualloadtest.ymlworkflow;docs/LOAD_TEST.md. - Legacy import tool (P8-T06, D-21):
@wirebloom/legacy-importCLI with a snapshot reader (JSONL manifest orpg_dump --data-only), deterministic mapping plan and PII-free report, customers → operator customers with queued invitations and KYB snapshots, beneficiaries → encrypted recipients with duplicate collapse, balances → opening journal entries againstLegacy migration <CCY>suspense accounts (reconciled per currency), history → monthly statement PDFs, idempotent resumable apply with audit and compensating rollback, synthetic generator with the audit quirks; 76 tests;docs/LEGACY_IMPORT.md. - Web API mismatches (P6-T01 follow-up): contract 1.0.0-draft.6 (302 paths, 399 operations, 502 schemas): journal items carry lines, idempotency keys released on 401/403/429 so a step-up retry succeeds, typed
TransactionExportFilter, document filters, scheduledwithTotal,Recipient.approvalwithcanDecide,Approval.received,ScheduledPaymentTemplate.recipientName,GET /payments/{id}/approvals, primary-owner transfer reads,Team/IntegratorWebhook.updatedAt, defaulted fields optional in generated types,bacsrail end to end (migration 0026), pushchannelId/categoryIdper category. - Staff mobile approvals (P9-T03): staff mode in the Expo app (mode detection from operator memberships, protected route sets, 30-minute idle sign-out persisted across cold starts), unified queue over payment actions, recipient approvals, KYB decisions, limit exceptions and monitoring alerts with step-up before every decision and per-decision idempotency, read-only customer summaries, staff push routing and
operationschannel, Maestro staff flow; 281 mobile tests. - Customer web screens (P6-T01): Home, Balances with account details, Transactions (filters, saved filters, column chooser, export jobs, drawer with annotations/labels/attachments/confirmation), Statements, Payments hub with send/add money/exchange/transfer/bulk wizards, scheduled payments with RRULE builder, forward contracts and held rates, direct debits (collections), cards placeholder, limits, Recipients with requirements-driven wizard and CoP override, Requests (approvals inbox, funds requests), People and teams, all Account settings sections incl. API keys/webhooks and approval-policy tiers, notifications centre; capability/flag-aware navigation; per-area message catalogues; 432 web tests, 5 enabled Playwright flows + axe sweep; passkey step-2 fix (N55).
- Mobile release pipeline (P7-T04): EAS profiles with fingerprint runtime versions and update channels, release-check script, Sentry (errors only, parity scrubber), encrypted MMKV cache with Expo Go fallback, Keychain purge on reinstall, OS-level certificate pinning plugin (pins supplied by owner), screenshot protection and clipboard auto-clear, device-integrity advisory, Android notification channels and approval actions, forced-update gate,
.github/workflows/mobile.yml,docs/MOBILE_RELEASE.md; 241 mobile tests. - Coord: full monorepo gate 86/86 tasks, prettier clean, schema no diff (2026-09-23 late evening).
- Console and mobile API gaps (P6 prep): contract 1.0.0-draft.4 (300 paths, 396 operations, 500 schemas) with typed reports, dashboards, provider connection config/credentials per adapter (JSON Schema from zod), monitoring params and operator settings; staff reads on balances/payment events/approvals;
/ops/customerswith issue counts, communication log,/ops/staffand/ops/staff-roleswith subset validation, operator-readable provider catalogue, fee catalogue item ETags,GET /notifications/{id}, RFC 7009 revoke, mobiledeviceId/expiresIn/refresh-token-reused,Health.minimumAppVersion, exchange confirmation as PDF,data.tenantIdon notifications,Device.current; 747 api tests. - Mobile features (P7-T02 + P7-T03 client side): TanStack Query with encrypted-session-gated AsyncStorage persistence and tenant-scoped keys, all customer screens (balances/account details, activity with filters/exports/statements, transaction detail with notes/attachments/confirmation share, recipients wizard with on-device bank validation and CoP display, send/add money/exchange/transfer/scheduled, approvals and funds requests, notifications centre/preferences/devices, settings incl. biometric lock and sessions, onboarding status with Sumsub WebSDK in a hardened WebView and optional MobileSDK launcher), push handling with safe deep links and badge, Maestro flows written; 192 tests; typed routes checked in CI.
- Reconciliation (P5-T04): per-connection runs with persisted cursors, every booking matched/suspended/excepted exactly once (property-tested), missed webhooks applied through the existing engines, balance comparison with in-flight tolerance and drift alerts feeding
ledger.integrity, exception resolutions (allocate, match, write-off with dual control, ignore) with step-up and idempotency, failed-webhook replay and adapter recovery (recoverWebhooks?), migration 0023 (reconciliation_balances,reconciliation_cursors, new exception kinds); 14 worker + 7 api tests;docs/runbooks/RECONCILIATION.md; review items M-14 resolved, M-09 mostly resolved, M-05/M-06 mitigated. - Operator console (P6-T02) and provider connection console (P5-T03): 36 routes: dashboards, customers with nine tabs (standing, people/impersonation, balances, payments, limits editor, pricing, notes, documents), KYB review queue with decisions and screening, payment operations with actions and exceptions (payment, limit, monitoring), recipient approvals, journal with manual postings (dual control, step-up) and reconciliation views, pricing (typed rule editor with preview, customer pricing, billing runs, fee charges, settlements, ERP export), reports runner, audit log, staff, operator settings, white-label branding with live preview and domains, provider connections (schema-driven wizard, write-only credentials, test/capabilities, routing rules validated against capabilities, events replay, KYC connections); 13 vitest suites + 4 axe suites, 7 Playwright ops flows, 5 screenshots.
- Banking Circle adapter (P5-T01) and batch CSV adapter (P5-T05): full
BankingProviderfor Banking Circle Connect from the crawled documentation (mTLS/Basic token cache, master accounts and VIBAN pool with customer-details modification guard, credit-transfer instructions with idempotency replay handling, status mapping with attention flags, cancel/recall, RFQ/held-rate FX with cross-process quote ids, SDD direct debits, AES-256-GCM webhook verification, camt.053 + bookings reconcile) with 40 HTTP fixtures and a no-network scripted transport; operator-run batch rail with export/import formats; registry now lists sandbox, banking-circle, integrated-finance, batch-csv; providers package 308 tests;docs/runbooks/BANKING_CIRCLE.md; INTEGRATIONS §4.1/§4.3 rewritten. - Integrated Finance adapter (P5-T02): full
BankingProvideragainst the public documentation with 61 recorded-style fixtures and a scripted transport: RS256 assertion auth with single-flight token cache, clients and accounts, deposit info, statements with organisation-side filtering, beneficiaries/requirements/CoP/VoP, outgoing transfers with idempotency and compliance checks, exchange quotes/transactions, generic transactions, Ed25519 webhook verification against the published key, failed-webhook recovery, reconcile; 136 tests;docs/runbooks/INTEGRATED_FINANCE.md; INTEGRATIONS §4.2 rewritten. - Mobile scaffold (P7-T01): expo-router auth and app stacks, native two-step login with TOTP/recovery and first-login enrolment, browser PKCE sign-in with https app links, in-memory access token and biometric-gated refresh token in secure storage with single-flight rotation, step-up sheet with retry, operator branding with contrast parity to the web, version gate, push device registration, brand icon/splash, privacy manifest placeholders; 99 tests;
expo exportfor both platforms andexpo-doctorclean. - Security fixes (P4-T15): impersonation bound to the target membership (S-01), explicit money-movement classification under impersonation (T-01), client-IP trust by CIDR plus signed BFF viewer header and account-keyed per-IP buckets (S-02), URL token masking in logs/spans (S-03, S-10), fastify override to 5.12.5 with a blocking audit gate (S-04, S-30), MFA-reset role guard (S-06), per-account MFA failure lock (S-07), CSV formula guard (S-08),
__Host-cookie prefix (S-17), worker log redaction (S-25/26); SECURITY.md §1.4 and ENVIRONMENT.md updated. - Activity and reports (P4-T12): unified transactions read model as a
security_invokerSQL view with one filter function shared by list, totals and exports, keyset paging, detail timeline, annotations/labels/attachments, async CSV/XLSX exports (dependency-free XLSX writer) as jobs, monthly statement job and CSV/XLSX statements, cached branded confirmations,/jobs/{id}, staff reports catalogue with CSV exports, five dashboards with 60 s cache, scoped audit log; migration 0021 (transaction_metadata,confirmations, view and function); 17 e2e + 12 worker tests. - Coord: drizzle snapshot regenerated as 0022 after the six-migration wave;
generatereports no schema changes. - Public API (P4-T14): API keys (once-shown secrets, scopes, expiry, IP allow-list, rotation with grace, revoke, per-customer limits), integrator webhooks (HTTPS + SSRF guard with resolve-time checks and pinned connections, KMS-wrapped secrets with 24 h dual signing, contract retry schedule, pause after 20 failures, disable on exhaustion, deliveries and redelivery), trigger-based event capture into
integrator.*outbox topics with fan-out, sandbox simulations through the real provider-event pipeline,wb_test_keys gated per environment; sample integration client underplatform/examples;docs/api/INTEGRATORS.md; migration 0022; 22 e2e + 8 worker tests. - Exchange (P4-T08): quotes with operator FX spread and domain rounding sides, execution and settlement postings in the worker (fx_clearing residue as FX result), confirmation render, held rates and forward contracts (deposit sub-balance, drawdowns, maturity, margin calls) gated by capability and the
fx.forwardsflag, add money by conversion, cross-currency payment quote binding in preparation; migration 0018 (exchange_drawdowns); 26 e2e + 13 worker tests. - Scheduled payments and direct debits (P4-T09): standing orders on a date-based RRULE subset with business-day adjustment and time zones, hourly occurrence generation with idempotent occurrence rows, worker instantiation mirroring payment preparation, 3-failure inactivation, operator pre-approval setting; mandates (encrypted debtor identifiers, references, client-managed), collections with scheme lead times, submission, event/poll status, settlement postings, return windows and reversals, mandate expiry; migration 0019 (
scheduled_occurrences); 28 e2e + 14 worker tests. - Limits and monitoring (P4-T11): effective-dated limit sets (operator defaults, customer overrides, tombstones) with contract field mapping, usage rollups in the operator timezone from a payments trigger + outbox (
limit_usage, closes N46), limit exception queue resolved through the payments ops service, five monitoring rules with alerts and KYC re-screen hooks; migration 0020 (recreateslimits_scope_uniqueand the bound check: accepted pre-launch); 14 e2e + 7 worker tests. - Approvals and funds requests (P4-T07):
/approvalsinbox for payments, bulk batches, recipients, funds requests and primary-owner transfers with tier snapshots,approval_decisionsrows folded through the domain (maker refused withdual-control, role/team eligibility), step-up on approve, expiry and reminder worker jobs, notifications to qualified approvers; funds requests with policy tiers, immediate fulfilment by internal transfer, cancel and expiry; migration 0017; 20 e2e + 4 worker tests. - Payments (P4-T06): creation with recipient/currency/limit/approval/routing/cut-off checks and hold placement, conditional step-ups, idempotent replay, dry-run with fee quotes, drafts, submit/cancel, transfers, add money (same currency), bulk CSV (streaming validation, per-row results, batch approval), operator queue with execute/hold/release/recall actions, exceptions queue (stuck, limit tolerance/queue, provider error, unmatched incoming, return unmatched), incoming credits with suspense allocation, returns linked to originals; worker payments engine (submit, poll, scheduled release, stuck detection, bulk validate) calling the ledger functions and fees; provider event hand-off through the webhook chain; domain payment references and CSV parser; migration 0015 (
payment_exceptions,bulk_upload_rows, manual-posting columns); 23 e2e + 18 worker integration tests. - Coord: payment-events handler bound into the webhook chain; providers e2e keeps a queue-only dispatcher via Nest overrides; billing test customer-number flake fixed.
- Fees and billing (P4-T10): fee catalogue, effective-dated pricing templates with typed rules (fixed, percentage min/max, tiered, per-rail, FX bps, monthly, card custom), customer pricing assignments and overrides,
FeeQuoteProviderfor payments, fee charges posted through the ledger with waive/refund reversals, monthly billing runs with pro-rating and funds-required items settled on incoming funds, fee settlement to operator ops, fee-income and ERP CSV exports as documents; worker jobsbilling.monthly-run,billing.settle-pending,billing.settlement; migration 0016. - Ledger service (P4-T02):
PostingService(post, holds with partial capture, release, reverse, replay-safe),LedgerService(race-safe main balances, pots and pot transfers, operator singleton accounts, provider mirrors, account status machine, currency enablement),BalanceQueryService(balances, holds, journal with running balance, account details per rail, statement data), accounts routes per contract, manual postings with dual control, read-only reconciliation views, worker jobsledger.integrityandledger.provision-customer(consumescustomer.approved), migration 0012 (ledger.integrity_runs, provider reported balances, statement jobs); SQL/in-memory template parity test and the 100-parallel-payments acceptance test. - Coord: Sumsub webhook handler bound in front of the Resend handler; test worlds gained a provider-override hook; full gate 76/76.
- Onboarding and KYB (P4-T03):
@wirebloom/kyc(KycProvider interface, Sumsub adapter with HMAC signing, applicant lifecycle, review mapping, screening flags; deterministic sandbox adapter), KYB wizard per contract (/customers/{id}/kyb/*), submission snapshots, RFI round-trips, operator review queue with decisions and screening resolution, provider recommendations with optional auto-approve, Sumsub webhook handler, worker jobsonboarding.provision-customer(IF/sandboxcreateCustomer, Banking Circle VIBAN details with the 2-modifications guard) andonboarding.screening-refresh, outbox eventcustomer.approved; migration 0014; 16 e2e + 6 integration tests. - Phase 3 consolidation (P3-T16): contract 1.0.0-draft.2 (257 paths, 345 operations) with every backlog item applied, branded identity emails,
impersonation.id, email-change confirm, Resend and Sumsub handlers bound to the webhook dispatcher,wb_pgbossrole and weak-password refusal in migrate, RDS CA bundle in images, telemetry hooks, MFA secrets on@wirebloom/cryptowith dual read andsecrets.rotate-mfa, jobsidentity.purge-expired,tenancy.domains.verify,balances.watch-low, vitest presets and measured coverage floors, signed-in e2e smoke. - Recipients (P4-T05): requirements per currency/country from the routed connection with a static fallback table and alternatives, envelope-encrypted identifiers with per-operator HMAC duplicate detection, masked listings with audited full reads, CoP/VoP verification with stored outcomes and overrides, approval modes customer/operator/none through the domain machine and
tenant.approvals, provider beneficiary refs per connection,requireApprovedand auditedsnapshotForPaymentfor payments; migration 0013; 20 e2e tests. - Tenancy administration (P4-T04): operator branding with server-side WCAG validation and logo documents,
GET /public/brandingby verified host (cache, ETag, never 404), web domains verified by DNS TXT, sender domains through a Resend-backed provider, operator settings in contract shape, platform administration (operators status machine, plans, flags) with access reason and audit, customer standing changes by staff, settings export, keyset paging, alert trigger cooldowns; migration 0011 (platform.operator_domains); seeds mapped to contract branding keys with new capability rows. - Domain package (P4-T01): money extensions (bps, percentage, FX with explicit rounding sides, splits), typed error hierarchy mapped to problem types and ledger SQLSTATEs, ledger model with 20 posting templates and an in-memory mirror of
0003_ledger_functions.sql, 17 table-driven state machines with generated Mermaid diagrams and provider status mapping, routing and cut-off evaluator, fee rules and billing planner, limits with tolerance bands, approval tiers; 537 tests, coverage 99.9 % lines, enum-parity test against the db enums and the contract. - Observability (P3-T09):
@wirebloom/telemetry(OpenTelemetry SDK with health-aware sampling, OTLP traces/metrics/logs, pino correlation, three-layer redaction incl. Luhn/mod-97 scrubbing, low-cardinality metric helpers, Sentry errors-only,--importpreload), local stack (collector, Tempo, Loki, Prometheus, Grafana) with six dashboards and 14 alert rules with promtool tests, staged database-outage alert recorded;docs/OBSERVABILITY.md. - Web shell with auth (P3-T12): BFF route handler proxy to the API, two-step login with TOTP/passkey/recovery, first-login TOTP enrolment with recovery codes, password reset, email verification, invitation acceptance, choose-account and tenant switcher, step-up modal with request retry, session-expired redirect, impersonation banner, runtime operator branding, notification bell wiring, My details page, next-intl scaffold, TanStack Query data layer;
@wirebloom/uigainsIbanInput,PhoneInput, bulk-selection bar, brand theming, hydration-safe Toaster (N19); Playwright login flows (first sign-in, two accounts, expiry, impersonation) green against the real API. - Storage and PDF (P3-T13):
@wirebloom/storage(S3/MinIO and filesystem object stores, pre-signed PUT with signed type/size/SHA-256 headers, allow-list and magic-byte checks, clamd streaming scanner with fail-closed retries, quarantine, document lifecycle, retention),@wirebloom/pdf(react-pdf statements and confirmations with bundled fonts and byte-identical golden files), API documents module (intent → complete → scan → download; infected → 422document-not-clean, audited), worker jobsdocuments.scan/render/retention; migration 0010; compose profilestorage(MinIO, ClamAV). - Tenancy and authorization (P3-T06): real
TenantGuardwith membership/API-key/platform (X-Access-Reason) resolution, per-request RLS transaction interceptor, CASL abilities from role_capabilities + operator overrides + custom roles + feature flags,CapabilityGuard, impersonation policy, tenants module (operators, customers, people, teams, invitations, settings, primary-owner transfer, closure),/mecompletion, staff MFA reset, Postgres stores wired viaAppModule.withPostgres, migration 0008 (refresh tokens, custom roles, primary-owner transfers, purge function), 50 tenancy e2e tests, api coverage floor 85%. - Notifications (P3-T14): typed template registry (15 React Email templates + digest) with operator branding, preference resolution with locked security categories, transports resend/smtp/capture, Expo push with receipts, Web Push (RFC 8291) with host allow-list, outbox-driven worker jobs (dispatch, deliver email/push/webpush, digest, receipts, retention), API centre/preferences/devices/test-send, Resend webhook handler with suppression list; migration 0009.
- Infrastructure (P3-T03): Terraform for staging/production in eu-west-2: network with fixed NAT EIPs, KMS, Secrets Manager containers, S3, RDS Multi-AZ, internal ALB + WAF, ECS Fargate (read-only root, circuit breaker, autoscaling, migrate task), CloudFront VPC origins, Route53/ACM, GitHub OIDC roles, ECR in a tooling account, CloudWatch alarms, budgets, AWS Backup with cross-region copies; bootstrap and tooling stacks; tftest, tflint, checkov, Trivy clean;
docs/ENVIRONMENT.md. - Identity (P3-T05):
@wirebloom/authon better-auth with hashed-session adapter, Argon2id, password policy with breach check, TOTP (RFC 6238), WebAuthn passkeys, recovery codes, PKCE, 15-minute access tokens with rotating refresh and reuse detection, step-up; API identity module (24/authroutes,/me, impersonation with reason and audit), AuthGuard before RateLimitGuard, lockouts, invitations with approved domains, request-scopedDatabaseServicerunning requests inside RLS transactions aswb_app; 12 e2e scenarios on Postgres. - Test harness (P3-T10):
@wirebloom/testkit(seeded factories, template-cloned test databases aswb_app, fake clock, notification capture, HTTP client builder, provider contract wrapper),@wirebloom/vitest-configpresets with per-package coverage floors and merged coverage gate,platform/e2ePlaywright project (desktop/phone, console guard, API booted on a seeded database, 13 critical flows catalogued, pending ones skipped with the enabling task); CI runs the coverage gate and both e2e suites. - Provider layer (P3-T15):
@wirebloom/providersfullBankingProviderinterface per INTEGRATIONS §2, typedProviderError, registry and client factory, HTTP client with host allow-list, retries with jitter and per-connection circuit breaker, sandbox adapter implementing every method, Banking Circle and Integrated Finance config schemas and capability skeletons, contract suite;@wirebloom/cryptoenvelope encryption (local and AWS KMS backends, rotation, fingerprints); API provider connections, routing rules withRoutingService.resolve, provider events and replay, KYC connections, inbound webhook receiver with Sumsub/Resend verifiers; migration 0007. - Contract:
ProviderConnection.credentialsFingerprint/webhookSecretSet, capability flags bacs/returns/statementsCamt053/currencies,GET /routes/{routeId}, nullableProviderEvent.connectionId, KYC connectionenvironment,sandboxwebhook slug. - Worker and jobs (P3-T08):
@wirebloom/jobs(typed definitions, envelopes, registry, run recorder, advisory-lock service, catalogue of 8 built-in jobs), worker runtime on pg-boss with DLQs, heartbeat health check, graceful shutdown, dead-letter CLI; Postgres stores for idempotency, rate limits, audit, feature flags, outbox and maintenance in@wirebloom/db/stores; migrations 0005/0006. - Design system (P3-T11):
@wirebloom/uitokens generated to CSS/Tailwind with AA contrast test, 45 components, Storybook (168 stories, axe on each), web shell with Home/Transactions/Recipients/Payments/Settings sample pages, search-param drawers, step-rail wizard, bottom nav, self-hosted fonts, Playwright smoke suite (17 tests). - Data layer (P3-T04):
@wirebloom/dbwith Drizzle schema for all 8 schemas (79 tables, RLS on every table, composite tenant FKs), roleswb_migrator/wb_app/wb_platform, migrations with advisory lock, ledger functions (post_entry, holds,reverse_entry,verify_integrity) with immutability triggers, partitioned append-only audit with sealed hash chain, seed, 40 tests incl. RLS isolation and posting invariants; real database health check. - CI/CD (P3-T02): root GitHub Actions (CI with Postgres service, migrations idempotence, Redocly/Spectral, gitleaks, audit, Trivy, image builds; staging and production deploys behind
AWS_DEPLOY_ENABLED, OIDC only, rollback), distroless Dockerfiles for api/worker/web, ECS deploy helper, git hooks (lint-staged, Conventional Commits), Dependabot, CODEOWNERS, PR template. - API skeleton (P3-T07): module per contract tag, cursor pagination, idempotency interceptor, ETag/If-Match, problem-type registry (46 types), rate-limit guard per SECURITY §1.3, capability/step-up/feature-flag metadata, audit emitter, API-key parsing, contract-drift test against
docs/api/openapi.yaml; typed client@wirebloom/contracts/clienton openapi-fetch with checked-in generated types. platform/monorepo scaffold (P3-T01): NestJS 11 (Fastify) API with problem details, zod validation, request context and health; pg-boss worker; Next 15.5 web shell with green tokens and shadcn; Expo SDK 54 mobile; packages domain (Money), contracts, providers (interface + sandbox + contract suite), ui, notifications (Resend, React Email); Terraform skeleton; docker-compose; 126 tests green.
Changed (10)
- Phase 10 close-out (commits
ae627b9,b07d896, 2026-09-24): contract1.0.0-draft.14(526 paths, 660 operations, 849 schemas; additiveHold.subject.type = payment_review,x-step-uponreplaceOperatorSettingsandreplacePlatformComplianceDefaults; integrator notes inapi/INTEGRATORS.md"Changes in draft.14"); the published contract (developer portal,/openapi.json) is the integrator subset only (105 paths, 126 operations, 206 schemas; no/ops,/platform,/compliance,/support,/internal,/mcppaths, nox-capability/x-step-up/x-feature-flag), the full contract is served only withDOCS_ENABLEDand a staff session (W3-09, D-52); customer-facing hold listings present compliance-gate and recall-case holds with subjectpayment_reviewand a neutral description (P10R-01, D-53); migrations 0048 and 0049 (when1790850000000). MASTER_PLAN: P5-T07…P5-T10, P9-T07, P9-T08b, P9-T09…P9-T11, P10-T01…P10-T06, P10-T08 and P10-T07 Completed (reviews/PHASE10_REVIEW.md§9), P9-T08 In Progress (N226); Phase 11 / 12 residual wave dispatched. - Phase 10 wave 2 integration (commit
74ce609): one customer document inbox/document-requestsfor partner-case and EDD requests (the interim EDD/compliance/document-requestsroutes were removed before release); one shared tipping-off guard for staff-written customer text (422 tipping_off);compliance.incomingruns in the worker @money queue group (D-51); purpose codes outside CNH accept any ISOExternalPurpose1CodeplusIPRT(W1-19);kyb.requireAllPersonsVerifiedchanges need a fresh step-up and no longer skip the customer's own KYC (W1-17);if.backfill,if.sync.drift,cases.apply-event,treasury.executearestatelyqueues (DEPLOYMENT §4.14); INTEGRATORS "Changes in draft.11" and "Changes in draft.12". - Provider connections (P5-T07, D-31/D-32): one
activeconnection per operator and environment; lifecycledraft→configured→testing→active→draining→retiredreplacesconnection_statusfor banking connections (statusno longer writable throughPATCH); routes become rail selection within the active connection (migration 0038 re-keysroutes_selection_uniqueper connection); supersedes the multi-connection routing of D-18 / P3-T15. Banking Circle adapter follows the recovered OpenAPI (P5-T10):BookedvsProcessedsemantics, bookings v3, reconciliation report as the nightly feed. Contract 1.0.0-draft.10 → draft.11. - Direction: rebuild from scratch as a multi-operator white-label SaaS banking platform (owner decision, D-00, D-13).
- Git remote switched to
https://github.com/implicitlabs/Wirebloom-Banking.git; old remote removed. - Legacy system moved to
backup/(git history preserved). - ARCHITECTURE aligned with the API contract: webhook path
/v1/webhooks/{provider}/{token}, ledger kinds, payment action routes, resource names; provider id naming rule (kebab-case in code and API, snake_case in the database enum). - Visual identity set to WireBloom green (owner instruction); Equals Money interaction model retained.
- Integration fix pass (backend, N59):
Device.currentcomputed onGET /devicesfrom the newtenant.notification_devices.session_id(migration 0025, nullable FK toiam.sessions, set null on delete, idempotent; set on everyPOST /devices); the worker exchange jobs no longer request the old order-confirmation render and the unusedExchangesService.confirmation()path is removed (GET /exchanges/{id}/confirmationrenders the PDF on demand;exchange_status/statement_readynotifications unchanged); worker notification tests expect the contractNotificationData(tenantId,template) in in-app and push data;money-gaps.e2eformatted. - Bulk payment submission is asynchronous (scalability audit X-12, D-38; commit
c3bc350):POST /bulk-payments/{bulkPaymentId}/submitreturns202BulkPaymentSubmitAccepted(theJobplus the batch insubmitting,Location: /v1/jobs/{jobId}) and a resumable worker runner creates the payments; contract1.0.0-draft.10. Timeouts by default (D-37): database statement / lock / idle-in-transaction, Fastify request, provider transport, BFF and mobile fetch budgets, config-driven; long jobs raise them withSET LOCAL.
Fixed (7)
- Phase 10 close-out blockers (commit
b07d896, 2026-09-24;reviews/PHASE10_REVIEW.md§8: 10 / 10 verified-closed, 0 reopened; gate 118/118): tipping-off in the customer holds view (P10R-01,payment_reviewsubject); remaining Banking Circle registration, token-rotation and deactivate calls moved out of the request transaction with a change lease onproviders.webhook_endpoints(P10R-02, migration 0049; N193 resolved); provider cost upsert shares the monthly close lock andpost_closefollows the line's month (P10R-03); open-banking refresh never mass-retires on a page cap, revoke intents expire (P10R-04); VIBAN details sync isolates failures, stale re-issue sweeper, stuck order intent alert (P10R-05); one-click unsubscribe limited per token (P10R-06); step-up on sensitive operator settings and platform compliance defaults with access reason, fresh step-up refuses without a session (P10R-07 a / b / d); developer registration timing oracle removed (P10R-08); concurrent status-page link answers 409 (W3-13). New residuals N298…N307. - Phase 10 wave 3 review findings (commit
ae627b9, 2026-09-24;reviews/PHASE10_WAVE3_REVIEW.md; gate 118/118): open-banking calls outside the request transaction with a committed revoke intent (W3-01); key-created customers gated by an invitation domain list and a rate limit (W3-02); step-up guard refuses API keys unless a route policy allows it, owners notified on webhook endpoint changes (W3-03, P4 S-14); operator-only simulated events refused for customer keys (W3-04); registration e-mail enumeration removed (W3-05); simulations and developer registration outside ambient transactions (W3-06, W3-07); only the integrator subset of the contract public (W3-09); stable unsubscribe tokens, RFC 8058 one-click, no incident cascade (W3-10…W3-14); step-up on platform writes, support role trimmed (W3-15); VIBAN reservation, re-issue, order intent and single-flight details push (W3-16…W3-20); late provider cost lines stamped post-close with alerts, cross-currency margin (W3-21…W3-23); TypeScript SDK sample app in CI (W3-27); operator gate rows re-floored by migration 0048 with step-up on the PUT (W3-28). Unfixed Low / Info rows in N297. - Phase 10 wave 3 (commit
95c6ded): wave 2 review fix-forward: BC recall accept records the intent before the partner call and reverses in its own transaction, partner-side ACCEPTED closure reverses or alerts (W2-01…W2-03); gate settings and hold rules floored by the platform (W2-04); incoming holds guarded in the DB (W2-05, 0047); IF decisions pushed outside the transaction (W2-06); sync status adoption through the customer and balance state machines (W2-07, W2-08); screening fails closed (W2-09); incoming credits screened before funds are available (W2-10); RFI answer outside the transaction (W2-12); batched recipient screening (W2-21); identity re-check path (W2-27); compliance tag in API.md (W2-30); worker README jobs (W2-53); unconfirmed treasury execution opens a reconciliation exception (W2-48 partial). Direct-debitsignedAtdate bug; N85, N86, N163. - Phase 10 wave 2 (commit
74ce609): N93 Integrated Finance hold captured onoutgoing-transfer-processing(reversed when a failure follows); cards webhook routing (pre-existing): card events stored under their provider type (cards/…,card-transactions/…) now reachcards.apply-event(D-51); wave 1 review fixes W1-01 (BC incoming credit double-post between webhook and reconciliation), W1-02 / W1-03 (treasury FX idempotency, claims and ledger holds), W1-04 (IF webhook key shadowing), W1-05 / W1-14 (BC return ordered before the ledger reversal,AlreadyReturnedrecovery, partner payment id), W1-06 (BC direct-debittownName), W1-07 / W1-08 (individual names from verified personal data, identity locked after applicant creation), W1-09 / W1-39 (BC IP allow-list at ingestion, live config regressions refused), W1-10 (deactivate counts mandates and settlement mirrors), W1-11 partly (per-connection webhook registration lock), W1-13 (BC credential rotation keeps webhook keys), W1-20 (draft.11 change notes), W1-21 / W1-22 (race, refusal and sole-trader payout tests, fixture citations). - Phase 10 wave 1 (commit
d4cea6c): N88 onboarding provisions only the active connection of the environment (provisioning holds released on activation); N89 Banking Circle returns callPOST /api/v1/returns; N90 all 17PaymentStatusvalues mapped (ScaPendingspelling,Hold→ compliance attention); N91 the 13 inferred Banking Circle fixtures rewritten and schema-validated against the recovered OpenAPI; N92 Integrated Finance V1/V2 webhook keys per environment built in; N87 closed by the console subscription lifecycle. Flaky tests: telemetry smoke hook timeouts; worker vitest timeouts and a template-database clone per suite. - Re-review follow-ups (PHASE11_12_REREVIEW.md): transient PostgreSQL errors (55P03/57014/40P01) answered as retryable 503 and retried in the worker; error serializer shared via
@wirebloom/telemetry/errorsin API, worker and MCP; migration 0034 idempotent with a CONCURRENTLY pre-build step;statelypg-boss policy for reconciliation and billing queues; BFF timeout applies to headers and idle body only; mobile token/revoke fetch timeouts; CSP upload origins reject wildcards;@ImpersonationAllowedremoved; DSR pre-check mirrors the shared-identity rule. - Security and scalability audit fixes (commit
c3bc350, 2026-09-24; full gate 106/106; Coord re-reviewreviews/PHASE11_12_REREVIEW.md: 0 FAIL, 4 PASS, 19 PASS-WITH-NOTES, follow-ups R-01…R-17). Security (reviews/SECURITY_AUDIT_2026-09.md): S-01 recipient identifiers bound at approval and re-checked at submission (recipient_changed;409on recipient edits while payments are in flight), S-02 limit-queued payments reopen the customer approval on staff release, S-03 DSR erasure keeps identities shared with other operators, S-04 role passwords set as client-side SCRAM verifiers, S-05 impersonation blocksself.profilewrites, S-06 per-customer advisory lock around limit checks, S-10 CSPconnect-srcincludes the S3 upload origin, S-11 BFF body cap (413) and streamed upstream responses, S-12 SQL parameters scrubbed from API error logs. Scalability (reviews/SCALABILITY_AUDIT_2026-09.md): X-01 per-operator incremental ledger integrity with checkpoints, X-02 set-based audit sealing and checkpointed chain verification, X-07 timeouts by default, X-11 (partial) partner calls moved out of the request transaction for quotes, recipient approval and KYB, X-12 asynchronous bulk submit, X-13 statements, X-14 reconciliation and X-15 (partial) billing fanned out per operator, X-16 (partial) and X-17 retention purges drained in bounded batches with supporting indexes, X-40 BFF/RSC upstream timeout, X-41 mobile fetch timeout. Migration0034_scale_readiness(journalwhen1790430000000). Residual items and follow-ups:MASTER_PLAN.mdP11/P12 rows, KNOWN_ISSUES N156…N159.
Security (1)
- Legacy exposures documented (12 Critical); containment tasks P1-T01…P1-T12 defined and blocked on owner access.