Skip to content

Fix execution-correctness bugs in RFQExecutionSaga#21

Open
devin-ai-integration[bot] wants to merge 1 commit into
masterfrom
devin/1780548392-fix-rfq-saga-execution-correctness
Open

Fix execution-correctness bugs in RFQExecutionSaga#21
devin-ai-integration[bot] wants to merge 1 commit into
masterfrom
devin/1780548392-fix-rfq-saga-execution-correctness

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Jun 4, 2026

Copy link
Copy Markdown

Summary

Audit + fix of RFQExecutionSaga and its collaborators (Bond, Counterparty) for fixed-income execution-correctness bugs. The REST contract is unchanged. ./mvnw clean verify is green: 16 tests pass (7 existing + 9 new).

Bugs found & fixed

1. Zero/negative/null amounts were never rejected — they corrupted inventory & credit.
The @Positive constraints on RfqDto.notionalAmount/executionPrice were never enforced because RfqController.createRfq has no @Valid. Worse, the entity guard only checked amount > available, so a negative amount passed the check and subtract(negative) increased balances:

deductNotional(-1_000_000)  ->  -1_000_000 > available? no  ->  available - (-1_000_000) = available + 1_000_000  // inventory inflated

Fix: the saga now validates both monetary inputs up front and throws a clear InvalidAmountException (HTTP 400) for null/zero/negative values, failing fast before any mutation. As defense-in-depth, Bond/Counterparty deduct*/add* also reject non-positive amounts, so availableNotional/availableCredit can never go negative even via the PATCH inventory/credit endpoints.

2. Monetary math had no explicit rounding / scale normalization.
DB columns are scale=2, but amounts were deducted in-memory at arbitrary precision, so the sufficiency check and the persisted value could disagree. Fix: amounts are normalized to 2 decimal places with explicit BigDecimal + RoundingMode.HALF_UP before being applied and stored. All money stays BigDecimal — no double anywhere (verified).

3. Atomicity of the two deductions — verified and locked in with a test.
Both deductNotional and deductCredit already run inside the single @Transactional boundary, so they commit or roll back together. There was no test proving it; added rollbackOnFailure_... which asserts that when credit is insufficient after notional was deducted, the bond's availableNotional is restored.

4. Clearer domain exceptions for unknown IDs.
ResourceNotFoundException now carries a message ("Bond not found: <id>" / "Counterparty not found: <id>"); the no-arg constructor is retained for existing callers.

New tests (RFQExecutionSagaTest)

happy path · insufficient notional (+state unchanged) · insufficient credit · rollback-on-failure · rounding (HALF_UP to cents, scale==2) · zero quantity · negative quantity (asserts inventory not inflated) · unknown bond · unknown counterparty.

Note: this test shares IntegrationTest's context config (@AutoConfigureMockMvc) so Spring reuses one cached context and the seed CommandLineRunner runs once against the shared in-memory DB (otherwise a second context re-seeds and hits a PK collision).

Notes

  • Branched off master (repo's default/main branch; there is no main).
  • No changes to REST paths or request/response shapes.

Link to Devin session: https://app.devin.ai/sessions/42802f33896449dca1fac83f9a6ffcfe
Requested by: @achalc


Devin Review

Status Commit
⚪ Not started

Run Devin Review

💡 Connect your GitHub account to enable automatic code reviews.

Open in Devin Review (Staging)

- Guard against zero/negative/null notional and price (validation was never
  enforced; negative amounts previously inflated inventory and credit)
- Normalise monetary amounts to 2dp with explicit BigDecimal HALF_UP rounding
- Harden Bond/Counterparty deduct/add to reject non-positive amounts so
  balances can never go negative (defends PATCH endpoints too)
- Add InvalidAmountException and clearer ResourceNotFoundException messages
- Add RFQExecutionSagaTest covering happy path, insufficient credit/notional,
  rollback-on-failure, rounding, zero/negative qty, unknown IDs

Co-Authored-By: Achal Channarasappa <achal.channarasappa@cognition.ai>
@devin-ai-integration

Copy link
Copy Markdown
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

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

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