Skip to content

fix(sync): store EnableBanking credit card debt as balance instead of available credit#2459

Open
mxafi wants to merge 3 commits into
we-promise:mainfrom
mxafi:fix/enable-banking-credit-card-balance
Open

fix(sync): store EnableBanking credit card debt as balance instead of available credit#2459
mxafi wants to merge 3 commits into
we-promise:mainfrom
mxafi:fix/enable-banking-credit-card-balance

Conversation

@mxafi

@mxafi mxafi commented Jun 22, 2026

Copy link
Copy Markdown

Fixes #2458

Description

Previously, the EnableBanking processor forcibly overrode the primary account balance for credit cards to be the available credit (credit_limit - debt) rather than the actual outstanding debt.

Because credit cards are correctly classified as Liability accounts dynamically within the application, this caused the balance sheet to incorrectly treat the user's available credit mathematically as a debt in their net worth calculation.

This PR aligns the EnableBanking processor with the existing Plaid and SimpleFIN processors by:

  1. Storing the absolute debt as the primary account balance.
  2. Tracking the available credit via accountable metadata so it remains visible but mathematically inert for net worth.

Summary by CodeRabbit

  • Bug Fixes
    • Improved how linked credit card cash balances are derived from the banking account’s current balance, using an absolute-debt interpretation.
    • Standardized credit card balance normalization so the cash balance consistently reflects positive outstanding debt.
    • Updated available credit handling: when a credit limit exists, available credit is recalculated from the limit; when absent, any previously stored available credit is preserved while cash balance still updates from the banking account.
  • Tests
    • Updated processor tests to match the revised credit card balance and available credit behavior.

… available credit

Previously, the EnableBanking processor forcibly overrode the primary account balance for credit cards to be the available credit (credit_limit - debt) rather than the actual outstanding debt. Since credit cards are modeled as Liability accounts, this caused the balance sheet (net worth) to treat available credit mathematically as a debt.

This PR aligns the EnableBanking processor with the Plaid and SimpleFIN processors by storing the absolute debt as the account balance, while tracking the available credit via accountable metadata.

Fixes we-promise#2458
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5071a8d9-36ba-45f3-9358-547b95c02289

📥 Commits

Reviewing files that changed from the base of the PR and between a906dd1 and feb816d.

📒 Files selected for processing (1)
  • app/models/enable_banking_account/processor.rb
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/models/enable_banking_account/processor.rb

📝 Walkthrough

Walkthrough

The CreditCard branch in EnableBankingAccount::Processor#process_account! is changed to store balance as balance.abs (the absolute debt) instead of overwriting it with available_credit. available_credit is now computed independently from credit_limit or the accountable's stored value. Tests are updated to assert the new behavior across three scenarios.

Changes

Credit Card Balance Fix

Layer / File(s) Summary
Balance normalization in CreditCard processor logic
app/models/enable_banking_account/processor.rb
Processor now sets balance = balance.abs and computes available_credit from credit_limit or stored value without altering balance. Previous logic that overwrote balance with available_credit and fallback derivation from available_credit - outstanding are removed.
Test expectations for balance and available_credit updates
test/models/enable_banking_account/processor_test.rb
Tests assert cash_balance equals the banking account current_balance (absolute debt) and verify available_credit is preserved or recalculated independently across three scenarios: credit limit present, limit absent with stored available_credit, and both absent.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐇 Hop hop, the ledger was wrong,
Available credit sang the balance song,
But debt is debt and abs makes it clear,
The liability sheet no longer needs fear.
A small fix for truth — the rabbit hops on! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: fixing how EnableBanking credit card debt is stored as balance instead of available credit.
Linked Issues check ✅ Passed The PR implementation directly addresses issue #2458 by fixing the processor to store absolute outstanding debt as balance and track available credit separately via metadata.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the credit card balance/available credit issue described in the linked issue #2458.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@superagent-security

Copy link
Copy Markdown

Superagent didn't find any vulnerabilities or security issues in this PR.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/models/enable_banking_account/processor.rb (1)

44-47: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Stale comment contradicts the new behavior and should be updated.

The comment states that available_credit "overrides the 'balance' variable" and instructs maintainers "Do not revert this behavior." However, the fix specifically removes that override—balance is now set to the absolute debt, not available credit. Leaving this comment risks a future maintainer reintroducing the bug, thinking they are restoring intended behavior.

Update or remove the comment to reflect that balance now represents the outstanding debt, with available credit tracked separately in accountable metadata.

📝 Suggested comment update
-      # For liability accounts, ensure balance sign is correct.
-      # DELIBERATE UX DECISION: For CreditCards, we display the available credit (credit_limit - outstanding debt)
-      # rather than the raw outstanding debt. Do not revert this behavior, as future maintainers should understand
-      # users expect to see how much credit they have left rather than their debt balance.
-      # The 'available_credit' calculation overrides the 'balance' variable.
+      # For liability accounts, ensure balance sign is correct (positive = debt owed).
+      # CreditCard balance stores the absolute outstanding debt, matching Plaid/SimpleFIN behavior.
+      # available_credit is tracked separately in accountable metadata for display purposes,
+      # keeping it mathematically inert for net-worth calculations.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/models/enable_banking_account/processor.rb` around lines 44 - 47, The
comment block describing the CreditCards balance calculation behavior is
outdated and contradicts the current implementation. The comment currently
states that available_credit overrides the balance variable and instructs
maintainers not to revert this behavior, but the fix has changed balance to
represent the absolute outstanding debt instead. Update this comment to
accurately reflect that balance now contains the outstanding debt amount and
available credit is tracked separately through accountable metadata, ensuring
future maintainers understand the current intended behavior and are less likely
to inadvertently revert the fix.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@app/models/enable_banking_account/processor.rb`:
- Around line 44-47: The comment block describing the CreditCards balance
calculation behavior is outdated and contradicts the current implementation. The
comment currently states that available_credit overrides the balance variable
and instructs maintainers not to revert this behavior, but the fix has changed
balance to represent the absolute outstanding debt instead. Update this comment
to accurately reflect that balance now contains the outstanding debt amount and
available credit is tracked separately through accountable metadata, ensuring
future maintainers understand the current intended behavior and are less likely
to inadvertently revert the fix.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 03ebc599-d20a-44df-a9e4-1046acd560fe

📥 Commits

Reviewing files that changed from the base of the PR and between fdcd0c7 and bc7ee04.

📒 Files selected for processing (2)
  • app/models/enable_banking_account/processor.rb
  • test/models/enable_banking_account/processor_test.rb

Updates the inline processor comments to reflect the new behavior introduced by the previous commit, clarifying that outstanding debt is stored sequentially as the primary balance rather than the UX available credit overriding it.

@jjmata jjmata left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The net-worth correctness argument is solid — storing outstanding debt makes the liability calculation accurate.

A couple of things worth flagging:

Breaking display change for existing users — Anyone with an EnableBanking CreditCard account currently sees "available credit" as their balance. After this PR merges, the same field shows "outstanding debt." That's arguably more correct financially, but it will surprise users. Worth calling out in release notes or a migration notice.

Removed "else" branch — The old fallback path (no credit_limit, no stored available_credit) left balance as the raw API value. The new code always balance.abs-es before the conditionals, so that case becomes abs(raw_balance). That's probably fine but the deleted comment "Fallback: no credit_limit from API — display raw outstanding balance" was documenting a deliberate choice. A brief comment on the new balance = balance.abs line saying why it's unconditional (even without a limit) would help the next reader.

available = credit_limit - balance — In the new code, balance has already been abs-ed, so this computes limit - abs_debt, which is the available amount. That's correct. Just making sure the reader notices the ordering dependency: balance = balance.abs must run before the subtraction. No bug, but the code is order-sensitive in a non-obvious way.


Generated by Claude Code

@mxafi

mxafi commented Jun 23, 2026

Copy link
Copy Markdown
Author

@jjmata Thanks for the review!

  1. Breaking Display Change / Release Notes

    I agree that this will surprise existing EnableBanking users with liabilities, although I don't know how many there are (the bug is annoying and easy to see). Should the PR description or something else be changed by me so that the UX difference is communicated in release notes?

  2. Removed else branch & Order Sensitivity

    abs(raw_balance) is how the other Processors do it, EnableBanking was the odd one out. I will think of a comment or small refactor to make it more clear what is happening.

I will push a quick follow-up commit to maybe refactor the abs logic a bit and add inline comments clarifying:

  • Why we unconditionally apply .abs to the balance (to strictly standardize outstanding debt).
  • The intentional order dependency where the available credit math relies on the newly absolute-ed debt.

I'll get that commit pushed up today or tomorrow!

…EnableBanking processor

Refactors the debt polarity assignments to clarify why liability balances are strictly parsed as absolute positive numbers. Replaces the implicit ordering dependency between the '.abs' conversion and the 'available_credit' math with an explicit 'outstanding_debt' variable to prevent regression by future maintainers.
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.

Bug: EnableBanking credit cards sync available credit as balance instead of actual debt

2 participants