Skip to content

feat: core fund flow hardening — atomicity, idempotency, insider threat controls, polyglot event handling#27

Merged
munisp merged 2 commits into
basefrom
devin/1782245799-core-fund-flow-hardening
Jun 23, 2026
Merged

feat: core fund flow hardening — atomicity, idempotency, insider threat controls, polyglot event handling#27
munisp merged 2 commits into
basefrom
devin/1782245799-core-fund-flow-hardening

Conversation

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Summary

Hardens all remaining fund flow paths that bypassed the atomicity/safety middleware added in PRs #21-#26. Three new middleware modules + polyglot service updates across Go, Rust, and Python.

Non-atomic balance fixes (17 occurrences)

Replaced all JS-arithmetic balance updates (String(Number(balance) - amount)) with atomic SQL:

-- Before (race condition on concurrent requests):
SET balance = String(Number(row.balance) - amount)

-- After (atomic, fails if insufficient):
SET balance = CAST(CAST(balance AS DECIMAL) - ${amount} AS TEXT)
WHERE CAST(balance AS DECIMAL) >= ${amount}

Files: routers.ts (CBDC transfer/receive, stablecoin swap), stablecoinEnhanced.ts (10 debit paths), propertyEscrow.ts (5 escrow operations), temporal/activities.ts (2 saga activities).

New middleware: server/middleware/coreAtomicity.ts

  • generateIdempotencyKey(userId, op, ...args) → deterministic SHA-256
  • checkIdempotency(key) / storeIdempotency(key, result) → 24h TTL cache
  • recordCoreDoubleEntry(params) → TigerBeetle ledger (DB fallback)
  • publishCoreEvent(topic, key, event) → Kafka audit trail
  • auditCoreOperation(params) → orchestrates all three
  • CORE_TOPICS — 10 new Kafka topics for savings, CBDC, bills, airtime, batch, wallet, stablecoin

New middleware: server/middleware/insiderThreat.ts

  • requiresMakerChecker(amount, action) → dual auth for ops >$10K (2 approvers >$100K)
  • checkGeoTimeFence({countryCode, utcHour}) → CA/NG/US/GB/KE/GH/ZA, Mon-Fri 6AM-10PM UTC
  • checkDlpAccess(userId, records) → 100 records/query cap, 50 queries/hour
  • requestJitAccess(userId, reason) → 2h max, 3/day, auto-revoke

Router wiring

  • wallet.topup, savings.deposit, bills.pay, airtime.topup → idempotency guard
  • CBDC transfer → insider threat check (maker-checker + geo-fence) + auditCoreOperation
  • batch.process → insider threat check + per-payment execution with balance deduction

Polyglot services

  • Go (port 8200): 10 new topic constants in AllTopics, CoreFundFlowEvent struct, coreFundFlowHandler registered for all topics
  • Rust (port 8210): POST /verify/fund-flow — 5-check validation (amount_range, known_feature, valid_status, timestamp_present, user_id_positive) with risk assessment
  • Python (port 8170): POST /detect/fund-flow — velocity spike, high-value, amount outlier, rapid-same-op detection; GET /fund-flow/topics metadata

Tests

36 vitest assertions: middleware unit tests, file-level verification of SQL CAST patterns, idempotency wiring, insider threat wiring, Go/Rust/Python structural checks, auditCoreOperation integration.

npx tsc --noEmit → 0 errors.

Link to Devin session: https://app.devin.ai/sessions/64d054ae77da41e9a2b74d8593fa635c
Requested by: @munisp

…at, polyglot events

- Fix 17 non-atomic balance updates across routers.ts, stablecoinEnhanced.ts, propertyEscrow.ts, temporal/activities.ts (SQL CAST with WHERE guard)
- Add coreAtomicity middleware: idempotency cache (24h TTL), TigerBeetle double-entry, Kafka event publishing for 10 fund flow topics
- Add insiderThreat middleware: maker-checker (dual auth >0K), geo+time fencing, DLP, JIT access, WebAuthn support
- Wire idempotency to wallet.topup, savings.deposit, bills.pay, airtime.topup
- Wire insider threat controls to CBDC transfer and batch.process
- Go Kafka service: 10 new core fund flow topic consumers with CoreFundFlowEvent struct
- Rust stablecoin bridge: /verify/fund-flow endpoint with 5-check validation
- Python anomaly detector: /detect/fund-flow endpoint with velocity/outlier/rapid detection
- 36 vitest tests covering all changes (0 TypeScript errors)

Co-Authored-By: Patrick Munis <pmunis@gmail.com>
@munisp munisp self-assigned this Jun 23, 2026
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author
Original prompt from Patrick

https://drive.google.com/file/d/14K-94cZoOVgiYCUA-VympU-4_8IBqv2d/view?usp=sharing
extract the contents of the archive. List all the features of the platform

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

…bypass

Co-Authored-By: Patrick Munis <pmunis@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

Testing Results — PR #27: Core Fund Flow Hardening

Session: https://app.devin.ai/sessions/64d054ae77da41e9a2b74d8593fa635c
Approval: User clicked "Test the app"

Summary: 78/78 tests passed, 1 bug found and fixed

Phase Tests Result
TypeScript compilation (tsc --noEmit) 0 errors Pass
Vitest baseline (36 assertions) 36/36 Pass
Vitest adversarial (23 assertions) 23/23 Pass
Python anomaly detection (19 assertions) 19/19 Pass
Go/Rust structural verification All checks pass Pass
Phase 1-2: Baseline Verification

Vitest (36 assertions across 9 test suites):

  • CoreAtomicity middleware: idempotency key generation, cache store/retrieve, topic definitions, TigerBeetle recording, Kafka publishing, audit orchestration (7 tests)
  • Insider threat controls: maker-checker thresholds, geo-fencing, DLP limits, JIT access (8 tests)
  • Non-atomic balance fix: no String(Number( patterns in 4 files (4 tests)
  • Idempotency wiring: wallet topup, savings deposit, bill pay, airtime topup (4 tests)
  • Insider threat wiring: CBDC transfer, batch process (2 tests)
  • Go Kafka service: 10 topics, CoreFundFlowEvent struct, handler registrations (3 tests)
  • Rust bridge: FundFlowEvent struct, 5 verification checks, endpoint (3 tests)
  • Python detector: topics, endpoint, anomaly model (4 tests)
  • Audit integration: full pipeline (1 test)

TypeScript compilation: npx tsc --noEmit exit code 0, 0 errors

Phase 3: Adversarial Boundary Tests (23 assertions)

Maker-Checker exact boundaries:

  • $9,999.99 no approval required
  • $10,000.00 1 approver required
  • $99,999.99 1 approver
  • $100,000.00 2 approvers

Geo+Time fencing boundaries:

  • Hour 5 (before business) blocked
  • Hour 6 (start of business) allowed
  • Hour 21 (last business hour) allowed
  • Hour 22 (after business) blocked
  • Break-glass override at hour 3 allowed
  • Unapproved country CN blocked with reason
  • All 10 approved countries (US/CA/GB/NG/GH/KE/ZA/DE/FR/NL) during business hours allowed

DLP rate limiting:

  • Records capped at 100/query
  • 50 queries pass, 51st blocked with "queries/hour exceeded"

JIT access daily limit:

  • 3 grants succeed, 4th denied with "max 3 grants/day exceeded"

Idempotency cache:

  • Store + retrieve returns cached result
  • Same user, different op produces different key
  • Different user, same op produces different key

Negative pattern verification:

  • routers.ts: NO String(Number( balance patterns
  • stablecoinEnhanced.ts: NO String(Number( balance patterns
  • propertyEscrow.ts: NO String(Number( balance patterns
  • temporal/activities.ts: NO String(Number( balance patterns
  • All SQL CAST debit ops have WHERE balance >= guard

Cross-service topic consistency:

  • TypeScript, Go, Python all define same 10 topics
Phase 4: Python Anomaly Detection (19 assertions)

Standalone test replicating /detect/fund-flow endpoint logic:

  • Normal $100 tx: risk < 0.5, recommendation "allow", no anomaly, no signals
  • High-value $15K: "high_value" signal, risk >= 0.2
  • Velocity spike (51 ops/hr): "velocity_spike" signal, risk >= 0.4, anomaly detected
  • Amount outlier ($50K vs ~$99 mean with varied history): "amount_outlier" + "high_value" signals, anomaly detected
  • Identical amounts edge case: outlier NOT detected when std=0 (documented limitation)
  • Combined velocity + high-value: anomaly detected, recommendation != "allow", risk >= 0.6, both signals present
  • Rapid same operation (11x stablecoin_swap): "rapid_same_op" signal
  • Exact $10K boundary: NOT high_value (threshold is >, not >=)
Phase 5: Go/Rust Structural Verification

Go Kafka service (services/go-kafka-service/cmd/main.go):

  • 27 remitflow.* topic references (10 core + existing)
  • CoreFundFlowEvent struct with all 9 fields (EventType, TransactionID, UserID, Amount, Currency, Status, Timestamp, Feature, Metadata)
  • All 10 handler registrations: SAVINGS_DEPOSIT, SAVINGS_WITHDRAW, CBDC_TRANSFER, CBDC_RECEIVE, BILL_PAYMENT, AIRTIME_TOPUP, BATCH_PAYMENT, WALLET_TOPUP, WALLET_WITHDRAW, STABLECOIN_SWAP

Rust bridge (services/rust-stablecoin-bridge/src/main.rs):

  • FundFlowEvent struct with 7 fields
  • 5 verification checks: amount_range, known_feature, valid_status, timestamp_present, user_id_positive
  • 8 verified features: savings, cbdc, bill_payment, airtime, batch, wallet, stablecoin_swap, transfer
  • /verify/fund-flow endpoint registered
Bug Found and Fixed

JIT grant ID timestamp collision (insiderThreat.ts:271):

  • Bug: Date.now() used for grant IDs. Rapid successive calls at same millisecond produce identical Map keys, overwriting earlier grants. This allowed bypassing the 3 grants/day limit.
  • Fix: Replaced Date.now() with randomUUID() for guaranteed uniqueness.
  • Commit: 792a7e9 fix: use randomUUID for JIT grant IDs to prevent timestamp collision bypass

@munisp munisp merged commit 3200532 into base Jun 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant