refactor(parser): extract bill detectors and engine #106

Merged
TimCane merged 2 commits from feat/93-extract-bill-detectors into main 2026-07-07 11:55:53 +01:00
TimCane commented 2026-07-07 11:44:30 +01:00 (Migrated from github.com)

Summary

  • Extract the bill-side detection out of ReceiptParseEngine.Parse into its own layer under Parsing/Detectors, mirroring how A4 moved item parsing into IReceiptRule + ItemSelectionEngine (Phase A5 of #77).
  • GrandTotalDetector owns the positional grand-total selection: lowest total-word row by Box.Y, same-row tie takes the larger amount.
  • BillDetectionEngine anchors on that total, reads Tax/Tip/Service off the rows above it, drops subtotals/rollups/VAT breakdowns/intermediate totals/payment noise, parks bare charges, and hands back the remaining item rows as a BillDetection result.
  • The keyword detectors for tax/tip/service/category-rollup/payment-noise/lone-service-label already live in the A3 KeywordClassifier; the bill engine composes that classifier with the positional anchor rather than duplicating it.
  • ReceiptParseEngine.Parse is now candidate-building plus engine wiring; the ReceiptParser facade and OcrWorker call site are unchanged.
  • docs/06 and docs/11 updated to describe the new bill-detection stage. No wire-contract change, so docs/03-05 are untouched.

Test plan

  • dotnet build backend/BillSplitter.sln -warnaserror -> 0 warnings / 0 errors.
  • dotnet test domain suite green (86 passed), corpus byte-identical (35 passed); no expected.json changes. Integration tests are Docker-only and CI-run.

Closes #93

## Summary - Extract the bill-side detection out of `ReceiptParseEngine.Parse` into its own layer under `Parsing/Detectors`, mirroring how A4 moved item parsing into `IReceiptRule` + `ItemSelectionEngine` (Phase A5 of #77). - `GrandTotalDetector` owns the positional grand-total selection: lowest total-word row by `Box.Y`, same-row tie takes the larger amount. - `BillDetectionEngine` anchors on that total, reads `Tax`/`Tip`/`Service` off the rows above it, drops subtotals/rollups/VAT breakdowns/intermediate totals/payment noise, parks bare charges, and hands back the remaining item rows as a `BillDetection` result. - The keyword detectors for tax/tip/service/category-rollup/payment-noise/lone-service-label already live in the A3 `KeywordClassifier`; the bill engine composes that classifier with the positional anchor rather than duplicating it. - `ReceiptParseEngine.Parse` is now candidate-building plus engine wiring; the `ReceiptParser` facade and `OcrWorker` call site are unchanged. - docs/06 and docs/11 updated to describe the new bill-detection stage. No wire-contract change, so docs/03-05 are untouched. ## Test plan - `dotnet build backend/BillSplitter.sln -warnaserror` -> 0 warnings / 0 errors. - `dotnet test` domain suite green (86 passed), corpus byte-identical (35 passed); no `expected.json` changes. Integration tests are Docker-only and CI-run. Closes #93
Sign in to join this conversation.
No description provided.