--- issue: 018 title: "select-offer updateMany has no status filter — overwrites withdrawn/rejected offers back to 'rejected' corrupting status history" severity: major domain: Seller Offer labels: [bug, backend, major, data-integrity] status: resolved resolved: 2026-05-29 fix: "Added status: { $nin: ['withdrawn', 'rejected'] } to the updateMany filter in select-offer handler — preserves existing terminal statuses." status: open created: 2026-05-29 source: Doc vs Code Audit 2026-05-29 --- # 🟠 select-offer updateMany has no status filter — overwrites withdrawn/rejected offers back to 'rejected' corrupting status history **Severity:** major **Domain:** Seller Offer **Labels:** bug, backend, major, data-integrity ## Description The POST /purchase-requests/:id/select-offer route handler (routes.ts lines 1386-1395) uses updateMany with only {purchaseRequestId, _id: {$ne: offerId}} — no status filter. This can overwrite already-withdrawn or previously-rejected offers' status back to 'rejected', corrupting their status history. SellerOfferService.acceptOffer() correctly filters by status: {$in: ['pending', 'active']}. ## Current Behavior Selecting an offer via the select-offer endpoint corrupts previously-withdrawn offer records by setting their status back to 'rejected'. ## Expected Behavior The select-offer updateMany call should include a status filter: {$in: ['pending']} to only reject pending offers, matching the service-layer behavior. ## Reproduction Steps Create a request with one withdrawn offer and one pending offer. Select the pending offer via POST /purchase-requests/:id/select-offer. Verify the withdrawn offer's status is now 'rejected'. ## Affected Files - `backend/src/routes/routes.ts` ## References - [Doc vs Code Audit Report](../09%20-%20Audits/Doc%20vs%20Code%20Audit%20Report%20-%202026-05-29.md)