Skip to content

fix: Amazon multi-shipment charge matching and Monarch fallback#40

Merged
eshaffer321 merged 4 commits into
mainfrom
fix/amazon-multi-shipment-matching
Jun 28, 2026
Merged

fix: Amazon multi-shipment charge matching and Monarch fallback#40
eshaffer321 merged 4 commits into
mainfrom
fix/amazon-multi-shipment-matching

Conversation

@eshaffer321

Copy link
Copy Markdown
Owner

Summary

Four changes that together fix categorization of multi-shipment Amazon orders:

  • feat: per-shipment item assignmentGetItemsForCharge estimates each shipment's charge (subtotal × tax rate) and returns the correct item subset for that shipment, so splits show the right items per Monarch transaction
  • fix: validate LLM category IDs — guard against hallucinated category IDs from OpenAI/Anthropic that don't exist in Monarch
  • fix: mark transactions as reviewed=false — prevents Monarch's rule engine from re-firing and resetting categories after the sync sets them
  • fix: Monarch-side subset discovery fallback — when scraper charges don't sum to the order total (shipment posted after scraper ran), FindSubsetByTotal searches unmatched Monarch transactions via subset-sum to recover the match. New file: internal/domain/matcher/subset.go

Test plan

  • go test ./... -race passes
  • ./itemize amazon -dry-run -days 30 -force with AMAZON_ACCOUNT_NAME=amazon-wife shows 22 orders would be processed, including multi-shipment orders 112-7165040-1665851 and 112-9922593-0590612
  • Live run confirms [TEMP] Amazon transactions in Monarch are replaced with categorized splits

Adds CLIShipment type and GetItemsForCharge() on the Amazon Order
adapter. When the scraper provides shipment groupings, each Monarch
transaction in a multi-delivery order is split using only the items
that were in that box rather than pro-rating the entire order.

Falls back to all items when shipment data is absent or the order
has a single shipment.
Three bugs fixed:

1. LLM returns invalid category ID (e.g. "Uncategorized") instead of a
   Monarch numeric ID → Monarch API rejects the update. Fix: validate
   each returned ID against the loaded category list; fall back to name
   match, then empty string if unresolvable.

2. When category ID is empty (unresolvable), the handler still tried to
   set it on the Monarch transaction, causing an API failure. Fix: skip
   the CategoryID field in UpdateTransactionParams when the ID is empty
   so we still write notes but don't fail the order.

3. LLM occasionally returns extra categorization entries (hallucination)
   for orders with fewer items. The extra entries inflated categoryGroups
   to size >1, sending a single-item order through the splits path with
   only 1 split → Monarch "must be split into two or more" error. Fix:
   truncate LLM results to len(uncachedItems) in CategorizeItems, and
   cap the categoryGroups loop in CreateSplits to len(items).

Also updated the categorizer prompt to remove the Walmart-specific
framing and explicitly instruct the model to use exact IDs from the list.
…ization

After setting category/splits via the Monarch API, transactions left in
needsReview=true state are re-processed by Monarch's rule engine, which
resets the category back to the rule's target (e.g. [TEMP] Amazon).

Fix: set NeedsReview=false on UpdateTransaction for single-category
updates. For split updates, call a follow-up UpdateTransaction after
UpdateSplits to clear the review flag, since updateTransactionSplit
doesn't expose needsReview directly.
…arges

When the Amazon scraper returns charges that don't sum to the order total
(e.g. a shipment charge posted after the scraper visited the page), try
to find a matching set of Monarch transactions via subset-sum search before
giving up. Uses a 10-day date window and recursive backtracking over the
small candidate set (typically 1–5 transactions).

Also fixes a nil matcher panic in TestAmazonHandler_ProcessOrder_InvalidCharges —
the test now supplies a real matcher since the handler calls FindSubsetByTotal
on validation failure.
@eshaffer321 eshaffer321 merged commit 8fa8e4f into main Jun 28, 2026
4 checks passed
@eshaffer321 eshaffer321 deleted the fix/amazon-multi-shipment-matching branch June 28, 2026 03:10
@codecov

codecov Bot commented Jun 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 42.55319% with 135 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.28%. Comparing base (c814779) to head (6db29cd).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
internal/domain/matcher/subset.go 0.00% 44 Missing ⚠️
internal/application/sync/handlers/amazon.go 68.14% 29 Missing and 7 partials ⚠️
internal/adapters/providers/amazon/order.go 0.00% 26 Missing ⚠️
internal/adapters/providers/amazon/parser.go 0.00% 18 Missing and 1 partial ⚠️
internal/domain/categorizer/categorizer.go 72.41% 6 Missing and 2 partials ⚠️
internal/domain/splitter/splitter.go 33.33% 1 Missing and 1 partial ⚠️

❌ Your patch status has failed because the patch coverage (42.55%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main      #40      +/-   ##
==========================================
- Coverage   61.48%   60.28%   -1.20%     
==========================================
  Files          44       45       +1     
  Lines        5045     5200     +155     
==========================================
+ Hits         3102     3135      +33     
- Misses       1763     1878     +115     
- Partials      180      187       +7     
Flag Coverage Δ
unittests 60.28% <42.55%> (-1.20%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
internal/adapters/providers/amazon/provider.go 73.52% <100.00%> (ø)
internal/domain/splitter/splitter.go 90.00% <33.33%> (-1.41%) ⬇️
internal/domain/categorizer/categorizer.go 88.73% <72.41%> (-4.92%) ⬇️
internal/adapters/providers/amazon/parser.go 75.42% <0.00%> (-14.48%) ⬇️
internal/adapters/providers/amazon/order.go 60.46% <0.00%> (-15.27%) ⬇️
internal/application/sync/handlers/amazon.go 65.28% <68.14%> (-3.27%) ⬇️
internal/domain/matcher/subset.go 0.00% <0.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

1 participant