6.2 KiB
pkg/cart — mutation inventory
Every mutation file under pkg/cart/mutation_*.go plus the slice of cart
state it touches. The grouping is subjective ("Subscription lifecycle",
"Discount surface", etc.) — used as a starting point for collapsing the
file-per-mutation pattern flagged in agents.md. Move two related
mutations into one file first; if the test surface stays smaller than the
two-file version, the grouping is real.
| File | Concern | State it READS | State it WRITES |
|---|---|---|---|
mutation_items.go (mutation_add_item.go and mutation_remove_item.go merged; tests stay in mutation_add_item_test.go + mutation_remove_item_test.go) |
Line item add/remove | state.Items |
state.Items, state.UpdatedAt |
mutation_change_quantity.go |
Line item quantity | state.Items[idx] |
state.Items[idx], state.UpdatedAt |
mutation_clear_cart.go |
Wholesale clear | — | state.Items, state.Vouchers, state.UpdatedAt |
mutation_set_user_id.go |
Ownership | — | state.UserID, state.UpdatedAt |
mutation_set_cart_type.go (+ test) |
Cart type | — | state.Type, state.UpdatedAt |
mutation_add_voucher.go |
Discount surface | state.Vouchers |
state.Vouchers, state.LineTotals (re-eval), state.UpdatedAt |
mutation_set_custom_fields.go (+ tests) |
Custom K/V | state.CustomFields |
state.CustomFields, state.UpdatedAt |
mutation_set_recovery_contact.go (+ tests) |
Recovery | — | state.Recovery, state.UpdatedAt |
mutation_subscription_added.go |
Subscription | state.Items |
state.Subscriptions, state.UpdatedAt |
mutation_upsert_subscriptiondetails.go |
Subscription details | state.Subscriptions |
state.Subscriptions, state.UpdatedAt |
mutation_markings.go (mutation_line_item_marking.go and mutation_remove_line_item_marking.go merged) |
Markings apply/remove | state.Items[idx].Markings |
state.Items[idx].Markings, state.UpdatedAt |
Delete-test quick check
For any proposed grouping, ask: does deleting the merged file concentrate
complexity, or just move lines? For markings — yes, the shared logic
(cascade to pricing) makes the merge worthwhile, and the merge is now done
(see below). For voucher vs custom_fields — no, those read different
state and have different error contracts; keep separate.
What is already merged
pkg/cart/mutation_items.go (added 2025-07) — AddItem and RemoveItem
both touch state.Items and share the ErrPaymentInProgress,
decodeExtra, and getOrgPrice helpers. Merge passed the delete-test
checks: the receiver *CartMutationContext, same grain (*CartGrain),
same mutation-registry dispatch. Both mutation_*_test.go files remain
because they assert specific method behaviour, not generic package
behaviour. Verified: go test -count=1 ./pkg/cart/... clean (voucher test
which references ErrPaymentInProgress still green).
Table corrections when merging
When the two source rows collapsed into one, two corrections landed in the merge:
- AddItem's old READS column listed
state.Vouchers (for stacking). That clause was incorrect — voucher stacking isAddVoucher's concern, not AddItem's. The merge drops the clause because readingmutation_add_item.goconfirms AddItem only readsstate.Items. This is a documentation correction, not a behaviour change. - Both
State it READS / WRITEScolumns originally had(both)annotations to remind that two distinct mutations were sharing the row. After collapse the row already saysLine item add/remove, so the(both)markers are noise — dropped.
If a future merge lands, follow the same pattern: read the actual source to verify the row's claimed state surface, and prune label-noise before compressing two rows into one.
pkg/cart/mutation_markings.go (added 2025-07) — LineItemMarking and
RemoveLineItemMarking both touch state.Items[idx].Markings and share
the same item-lookup loop (find by ID, mutate Marking field). Merge
passed the delete-test: the shared write surface and identical error
contract ("item with ID %d not found") make the grouping real. No test
files existed for either mutation, so the test surface is unchanged.
Verified: go build ./pkg/cart/... and go test -count=1 ./pkg/cart/...
clean.
NOT to merge next
mutation_change_quantity.go looks like an obvious candidate for the next
merge (same receiver, same grain, same state.Items write surface). It
is not — quantity has a partial-line-drop arithmetic contract that
add/remove do not:
AddItemalways merges or appends; never sets quantity down.RemoveItemalways removes whole lines; never decrements quantity.ChangeQuantitymay drop a line entirely if quantity reaches 0.
If you merge ChangeQuantity first, doing the same delete-test check
yields: deleting the merged file leaves the partial-line arithmetic
logic stranded in Apply, which IS a real concentration (good). But
the inverse: if AddItem later grows a "decrement" edge case, the
merged file will balloon and a re-split becomes expensive. Either
keep ChangeQuantity separate, OR merge all three with the merge
scoped to a "line item lifecycle" package and the partial-line
arithmetic under a clearly-named helper.
How this maps onto a refactor
- Pick a row with shared logic (markings, subscription details).
- Move related mutations + their tests into one file under
pkg/cart/<concern>.go. - Re-run
go test ./pkg/cart/...— same assertions, smaller surface. - Update this table to reflect the new file layout.