feat(parser): de-duplicate repeated receipt copies #113

Merged
TimCane merged 5 commits from feat/100-dedup-copies into main 2026-07-07 15:32:07 +01:00
TimCane commented 2026-07-07 13:08:33 +01:00 (Migrated from github.com)

Summary

  • Add CopyDeduplicator (Parsing/Multiline): collapses a receipt photographed as stacked merchant/customer/kitchen copies back to one.
  • Fires only when the whole item list is K identical contiguous blocks (each at least two items) and keeping one block reconciles with the printed grand total while keeping them all does not - so a genuine repeat order (two of the same dish, or an ordered pair listed twice on a single-total bill) is preserved, since its one block would not reconcile.
  • Runs after the item rules, before the receipt is assembled; no wire-contract change.
  • New fixtures duplicate-receipt-copy (deduped) and repeated-order-not-copy (preserved). The existing corpus stays byte-for-byte green - including jack-daniels-gratuity, whose legitimately repeated dishes are untouched.
  • Docs: flip the duplicate-copies entry to current in docs/15; note the de-duplicator in docs/06; record the fixtures in docs/11.

Test plan

  • dotnet test backend/tests/BillSplitter.Tests -> 93 passed, 0 failed.
  • duplicate-receipt-copy fails without the de-dupe step (items appear twice); repeated-order-not-copy (identical blocks but a 2x total) confirms the reconciliation gate keeps a genuine double order intact.

Closes #100

## Summary - Add `CopyDeduplicator` (`Parsing/Multiline`): collapses a receipt photographed as stacked merchant/customer/kitchen copies back to one. - Fires only when the whole item list is K identical contiguous blocks (each at least two items) and keeping one block reconciles with the printed grand total while keeping them all does not - so a genuine repeat order (two of the same dish, or an ordered pair listed twice on a single-total bill) is preserved, since its one block would not reconcile. - Runs after the item rules, before the receipt is assembled; no wire-contract change. - New fixtures `duplicate-receipt-copy` (deduped) and `repeated-order-not-copy` (preserved). The existing corpus stays byte-for-byte green - including `jack-daniels-gratuity`, whose legitimately repeated dishes are untouched. - Docs: flip the duplicate-copies entry to *current* in docs/15; note the de-duplicator in docs/06; record the fixtures in docs/11. ## Test plan - `dotnet test backend/tests/BillSplitter.Tests` -> 93 passed, 0 failed. - `duplicate-receipt-copy` fails without the de-dupe step (items appear twice); `repeated-order-not-copy` (identical blocks but a 2x total) confirms the reconciliation gate keeps a genuine double order intact. Closes #100
Sign in to join this conversation.
No description provided.