Repository navigation
fix(frontend): split bulk purchase batches by cloud account #333
Description
Summary
The frontend still groups bulk purchases without account identity, while the backend now requires every plan-less execution to contain one cloud account. Mixed-account selections can therefore produce a purchase request that the backend rejects with HTTP 400.
Current behavior and evidence
Statically confirmed against main eac9a62a88d49cbb30abf1dc3943037dd1d58b0b while reviewing LeanerCloud/cloud-commitments-cli#2071:
frontend/src/recommendations.ts:4028-4035groups selected rows by provider, service, term and payment, but notcloud_account_id.frontend/src/app.tssubmits each resulting modal bucket as oneexecutePurchaserequest.internal/api/handler_purchases.go:2334callspurchase.SingleCloudAccountIDFromRecsand returns HTTP 400 on ambiguity.internal/purchase/execution.go:893-920rejects both multiple account IDs and a mix of attributed and unattributed selected rows.
The API rejection is intentional safety behavior added in LeanerCloud/cloud-commitments-cli#2072 for LeanerCloud/cloud-commitments-cli#1902. Do not relax it. This is a frontend contract mismatch, not evidence that a real purchase was made incorrectly. No live cloud purchase or browser reproduction was performed for this finding.
Steps to reproduce
- Load two purchasable recommendations from different cloud accounts with the same provider, service, term and payment.
- Select both and open the bulk purchase modal.
- In an isolated fixture-backed verification environment, intercept the resulting submission and inspect its recommendations: both accounts share one POST.
- Exercise the real backend validation with that body: it returns HTTP 400 requiring one purchase per account.
Expected behavior
Each submitted execution contains one account. The modal clearly represents the resulting per-account submissions, totals and approval outcome. Unattributed recommendations must not be silently assigned to another account.
Proposed fix
Include account identity in frontend grouping, or split submissions per account with matching modal representation. Cover both the ordinary bulk modal and fan-out path in frontend/src/recommendations.ts and frontend/src/app.ts. Preserve the backend guard. Add regression coverage using real frontend grouping and the backend request contract, including mixed attributed/unattributed rows.
Severity and priority
High severity, P1: a supported multi-account bulk workflow is blocked after the safety fix. Selecting one account at a time is a workaround. Scope is limited to multi-account users; estimated effort S; urgency this sprint.
References
- Discovery: fix(frontend): re-price purchase modal rows and stop submitting skipped fan-out buckets cloud-commitments-cli#2071 Fable 5.1 review and integration check
- Backend safety change: fix(purchase): refuse a plan-less execution whose recs span cloud accounts cloud-commitments-cli#2072 / fix(purchase): a two-account direct execute buys in the ambient host account cloud-commitments-cli#1902
- Related executor regression-test gap: LeanerCloud/cloud-commitments-cli#1920 (different scope)
Activity