Skip to content

fix: CRMCleaner silently corrupted complex amounts into wrong finite floats (#129) - #135

Merged
shivamlalakiya merged 6 commits into
PhilanthroPy-Project:mainfrom
slegarraga:fix/crmcleaner-complex-corruption-129
Aug 23, 2026
Merged

fix: CRMCleaner silently corrupted complex amounts into wrong finite floats (#129)#135
shivamlalakiya merged 6 commits into
PhilanthroPy-Project:mainfrom
slegarraga:fix/crmcleaner-complex-corruption-129

Conversation

@slegarraga

Copy link
Copy Markdown
Contributor

Closes #129

What happened (reproduced on current main)

CRMCleaner.transform turned 3+4j into -34.0 — sign flipped, imaginary part dropped, digits concatenated — via three guards missing in sequence (full root-cause chain in #129).

The fix (two layers)

  1. Element-wise complex guard in _coerce_currency_to_float: on object columns, cells that are actually complex are masked to NaN with a UserWarning before the string cleanup can mangle them. NaN + warning follows the documented "values that still don't parse become NaN" contract.
  2. Contract preservation: had_value is now captured before masking, so a column where nothing parses (all-complex included) still raises could not parse, exactly as documented.

Verification (executed)

Notes for review

  • No public API change; behavior only differs where it was previously silently wrong.
  • Happy to switch to hard-raising on any complex cell if you prefer strictness over tolerance — one-line change + test tweak.

A single np.complex128 cell (Excel/openpyxl formula round-trip) survived
the transform-time object-cast retry and reached the currency parser's
string path, where str(3+4j) == "(3+4j)" matched the parenthesised-
negative rule and produced a plausible but wrong -34.0 (PhilanthroPy-Project#129).

Two layers:
- element-wise isinstance(v, complex) guard on object columns masks the
  cells to NaN with a warning before any string cleanup;
- had_value is now computed before masking so an all-unparseable column
  still raises per the documented contract.

Verified: repro from PhilanthroPy-Project#129 now yields NaN + UserWarning; full suite
1843 passed / 23 skipped.

Signed-off-by: slegarraga <slegarraga@users.noreply.github.com>
@shivamlalakiya

Copy link
Copy Markdown
Contributor

Good root-cause fix, well tested (the whole-column-still-raises case especially). One gap before merge: AGENTS.md requires a CHANGELOG.md entry under ## [Unreleased] for every PR touching philanthropy/, and this one doesn't have one yet (you're already credited in CONTRIBUTORS.md). Could you add a line for the complex-value fix? Holding the merge until then.

Per AGENTS.md, every PR touching philanthropy/ needs an entry under
[Unreleased]. Describes the two-layer guard from this branch: element-wise
complex masking to NaN with a warning, and preserved raise-on-nothing-parses
contract.
@slegarraga

Copy link
Copy Markdown
Contributor Author

Done in 384f2ba: added the ## [Unreleased] entry under ### Fixed,
describing both layers (complex cells masked to NaN with a warning naming
them; all-unparseable columns still raise per the documented contract).
Thanks for taking a close look at the whole-column test.

@slegarraga

Copy link
Copy Markdown
Contributor Author

Heads up: main moved (congrats on landing #140!) and this branch picked up a stale-conflict flag, so I merged current main in and re-ran the full local gates: make ci green (1904 passed, 97.06% coverage) and make riskcov green (96%). The CHANGELOG now carries both our ### Fixed entry and the new ### Added section side by side, no manual untangling needed. PR shows conflict-free again.

@shivamlalakiya
shivamlalakiya merged commit 0c0d832 into PhilanthroPy-Project:main Aug 23, 2026
14 checks passed
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.

CRMCleaner.transform silently corrupts complex amounts into wrong finite floats

2 participants