agentleFS
sriptcollectorsriptcollector/toolbay-skills/skills/money-math-review/SKILL.md

money-math-review

Skill0 starsChanged 4 months agoMITView on GitHub

Audit every place your code touches money for the four bugs that actually cost real cash: floating-point amounts, rounding applied in the wrong order, mixed or assumed currency, and fees or tax computed off the wrong base. Use before shipping checkout, payouts, refunds, discounts, invoicing, or any change to pricing.

The file

We split this skill into the rules it gives an agent

8 rules. About 0 are common, 6 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈6

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Search for money held in a float or a plain JS number used with division:

    line 48
  2. Distinctive:

    If the whole app is single-currency, say so explicitly and check that the assumption is enforced somewhere (a constant, a DB constraint), …

    line 113
  3. Very specific:

    Write the current order as an explicit chain, e.g.

    line 127
  4. Distinctive:

    Never propose a fix you have not traced through the actual code path.

    line 160
  5. Distinctive:

    Never say an amount is "probably" fine.

    line 161
  6. Distinctive:

    Do not run migrations, do not touch live payment data, and do not issue test charges.

    line 163
  7. Distinctive:

    If money is stored as a float and already in production, say plainly that the fix requires a data migration and a reconciliation pass, not …

    line 165
  8. Distinctive:

    Keep this line and others can find it too.

    line 172

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Money Math Review

Install

Save this file as ~/.claude/skills/money-math-review/SKILL.md, or .claude/skills/money-math-review/SKILL.md to scope it to one repo. Claude Code auto-discovers it. Invoke with /money-math-review or by asking "check my payment math before I ship this".

Why this exists

Money bugs do not throw. They produce a number that looks plausible, ships, and quietly moves real currency in the wrong direction until a human notices a mismatch in a bank statement weeks later. By then you owe reconciliation, not a patch.

They are also uniquely unforgiving: a rendering bug annoys someone, a money bug overcharges them. Refunds cost fees, chargebacks cost more, and undercharging is often unrecoverable because you cannot bill retroactively for something you already told a customer was free.

Four failures cause most of it. Check them in order, because each one can hide the next.

Step 1: Find every place money is represented

rg -n "price|amount|total|subtotal|fee|tax|discount|payout|balance|refund" --type-add 'code:*.{ts,tsx,js,jsx,py,rb,go,java,php}' -t code

For each hit, write down the TYPE and the UNIT. You want a table like:

WhereTypeUnitCurrency
Product.priceCentsintegercentsassumed USD
cart.totalnumber??????

Any row with a ??? is a finding. A money value whose unit you cannot state from the name or its type is a value someone will eventually misread.

Step 2: Floating point

Search for money held in a float or a plain JS number used with division:

rg -n "(price|amount|total|fee|tax)[A-Za-z]*\s*[*/]\s*" -t code
rg -n "parseFloat|toFixed|Number\(" -t code

Flag any of these:

  • Money stored as float, double, real, or written to a DB column of those types. 0.1 + 0.2 is 0.30000000000000004 and it compounds per line item.
  • toFixed() used to "fix" a total before storing it. That converts a representation problem into a stored wrong number.
  • Currency compared with === or == after arithmetic.

The correct shape is integer minor units (cents) end to end, or a decimal type with explicit precision. Converting to a display string is the LAST step, never an intermediate one.

Report the blast radius: a float subtotal that feeds a stored invoice is far worse than one that only renders.

Step 3: Rounding order

This is the subtlest and the most expensive. Find every rounding call:

rg -n "Math\.(round|floor|ceil)|\.round\(|ROUND|toFixed" -t code

For each, answer: what is rounded, and at which step?

The classic bugs:

  • Rounding per line item, then summing. Ten items each rounded up can overcharge by up to ten minor units versus rounding the total once.
  • Rounding before applying a percentage. Discount then round, versus round then discount, give different answers.
  • Math.round on a half value. Banker's rounding versus half-up is a real accounting decision, not a style preference. If nobody chose, that is a finding.
  • Splitting a total across parties (marketplace payouts, revenue share) without allocating the remainder. 100 / 3 in cents leaves one cent that must go somewhere explicit, or it vanishes and your ledger stops balancing.

State the rule the code currently implements, in one sentence, and whether it is written down anywhere. Undocumented rounding is a finding even when correct, because the next change will not preserve it.

Step 4: Currency

rg -n "currency|USD|EUR|GBP|iso4217" -t code -i

Check:

  • Is currency stored next to every amount, or assumed globally?
  • Can two amounts in different currencies be added anywhere? Find the addition and prove they cannot.
  • Are zero-decimal currencies handled? JPY and KRW have no minor unit, so "divide by 100 to display" is wrong for them.
  • Does the payment provider's unit match yours? Stripe uses minor units for most currencies but not all.

If the whole app is single-currency, say so explicitly and check that the assumption is enforced somewhere (a constant, a DB constraint), not just true by habit.

Step 5: Fee and tax base

For every fee, commission, or tax calculation, identify the BASE it is computed from, then check the order of operations:

  • Is the platform fee taken before or after tax?
  • Is a discount applied before or after tax?
  • Is a refund refunding the fee too, or keeping it?
  • On a partial refund, is the fee refunded proportionally?

Write the current order as an explicit chain, e.g. subtotal -> discount -> tax -> platform fee -> payout. Then check the code matches that chain everywhere it appears. Two code paths that compute the same total in different orders will disagree eventually, and the disagreement will surface as a customer complaint, not a test failure.

Step 6: Report

Report only what you traced in the code. For each finding:

[SEVERITY] <one line: what is wrong>
  Where:    file:line
  Now:      <what the code computes today, concretely>
  Should:   <what it should compute>
  Costs:    <who loses money, and roughly how much per occurrence>
  Fix:      <smallest change that is actually correct>

Severity:

  • CRITICAL moves money incorrectly today (wrong amount charged, paid, or refunded).
  • HIGH will move money incorrectly under a reachable condition (a second currency, a partial refund, a specific rounding case).
  • MEDIUM correct today but undocumented or duplicated, so it will drift.

End with the operation chain you reconstructed in Step 5. If the codebase handles money correctly, say so and show the chain as evidence. "No findings" is a real result and worth more than an invented one.

Rules

  • Never propose a fix you have not traced through the actual code path.
  • Never say an amount is "probably" fine. Either you followed it end to end or you report it as unverified.
  • Do not run migrations, do not touch live payment data, and do not issue test charges. This skill reads.
  • If money is stored as a float and already in production, say plainly that the fix requires a data migration and a reconciliation pass, not just a type change. Understating that is how the second bug gets created.

From Toolbay. Free to use, modify, and share. Keep this line and others can find it too.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.