{"record":{"id":"d66bc6a2985691ba","repo":"sickn33/agentic-awesome-skills","slug":"out-of-stock","errorCode":null,"errorMessage":"Out of stock","messagePattern":"Out of stock","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"skills/fp-async/SKILL.md","lineNumber":148,"sourceCode":"\n## 2. Chaining Async Operations\n\n### The Problem: Callback Hell / Nested Awaits\n\n```typescript\n// BEFORE: Deeply nested, hard to follow\nasync function processOrder(orderId: string) {\n  try {\n    const order = await fetchOrder(orderId)\n    if (!order) throw new Error('Order not found')\n\n    try {\n      const user = await fetchUser(order.userId)\n      if (!user) throw new Error('User not found')\n\n      try {\n        const inventory = await checkInventory(order.items)\n        if (!inventory.available) throw new Error('Out of stock')\n\n        try {\n          const payment = await chargePayment(user, order.total)\n          if (!payment.success) throw new Error('Payment failed')\n\n          try {\n            const shipment = await createShipment(order, user)\n            return { order, shipment, payment }\n          } catch (e) {\n            // Refund payment? Log? What's the state now?\n            await refundPayment(payment.id)\n            throw e\n          }\n        } catch (e) {\n          throw e\n        }\n      } catch (e) {\n        throw e","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/sickn33/agentic-awesome-skills/blob/58d857988fcfac6986206bca2b2fe223aa437e4b/skills/fp-async/SKILL.md#L130-L166","documentation":"Illustrative domain error from the inventory step of processOrder: checkInventory(order.items) returned { available: false }, so the guard throws 'Out of stock'. The example shows how business-rule failures get modeled as exceptions in imperative code.","triggerScenarios":"Ordering more units than stock on hand; concurrent orders exhausting stock between check and charge; inventory sync lag making the service report unavailable.","commonSituations":"Flash sales causing races between checkInventory and chargePayment; warehouse sync delays; cart quantities cached client-side and exceeding current stock.","solutions":["Verify actual stock levels for the order's SKUs before retrying","Use optimistic locking or reservation so availability is atomic, removing the race","Model this as an expected Left (business rule) in a TaskEither pipeline instead of a thrown exception","Surface a user-facing 'item unavailable' message with per-item detail rather than a generic error"],"exampleFix":"// before\nconst inventory = await checkInventory(order.items)\nif (!inventory.available) throw new Error('Out of stock')\n// after\npipe(\n  checkInventoryTask(order.items),\n  TE.chain(inv => inv.available\n    ? TE.right(inv)\n    : TE.left(new Error('Out of stock')))\n)","handlingStrategy":"validation","validationCode":"const inv = await checkInventory(order.items)\nif (!inv.available) return { kind: 'OutOfStock', items: inv.unavailableItems ?? order.items }","typeGuard":"const isInventoryResult = (r: unknown): r is { available: boolean } =>\n  typeof r === 'object' && r !== null && typeof (r as any).available === 'boolean'","tryCatchPattern":"try {\n  // ...\n} catch (e) {\n  if (e instanceof Error && e.message === 'Out of stock') { /* restock / notify flow */ }\n  else throw e\n}","preventionTips":["Reserve stock atomically instead of check-then-charge","Re-check availability at payment time, not only at cart time","Return per-item availability so users see which SKU failed"],"tags":["documentation","domain-error","inventory","business-rule"],"backgroundTag":"business-rule-violation","analyzedSha":"58d857988fcfac6986206bca2b2fe223aa437e4b","analyzedAt":"2026-08-26T11:55:59.350Z","schemaVersion":2},"datasetVersion":"2026-08-26T14:46:13.012Z"}