{
  "filename": "webhooks.py",
  "rule": "- name: webhook-receipt-gates-side-effect\n  where: \"webhooks.py\"\n  ensure: >-\n    If the unique webhook receipt insert returns no row, apply_paid_event must return before changing any order.",
  "corrected": "from sqlalchemy import text\n\ndef apply_paid_event(engine, event_id, payment_session_id):\n    with engine.begin() as connection:\n        receipt = connection.execute(text(\n            \"INSERT INTO webhook_receipts (event_id) VALUES (:event_id) \"\n            \"ON CONFLICT (event_id) DO NOTHING RETURNING event_id\"\n        ), {\"event_id\": event_id}).scalar_one_or_none()\n        if receipt is None:\n            return \"duplicate\"\n        changed = connection.execute(text(\n            \"UPDATE orders SET status = 'paid' \"\n            \"WHERE payment_session_id = :session AND status = 'pending' \"\n            \"RETURNING id\"\n        ), {\"session\": payment_session_id}).scalar_one_or_none()\n        if changed is None:\n            raise ValueError(\"Expected pending payment session\")\n        return \"applied\"\n",
  "broken": "from sqlalchemy import text\n\ndef apply_paid_event(engine, event_id, payment_session_id):\n    with engine.begin() as connection:\n        receipt = connection.execute(text(\n            \"INSERT INTO webhook_receipts (event_id) VALUES (:event_id) \"\n            \"ON CONFLICT (event_id) DO NOTHING RETURNING event_id\"\n        ), {\"event_id\": event_id}).scalar_one_or_none()\n        changed = connection.execute(text(\n            \"UPDATE orders SET status = 'paid' \"\n            \"WHERE payment_session_id = :session AND status = 'pending' \"\n            \"RETURNING id\"\n        ), {\"session\": payment_session_id}).scalar_one_or_none()\n        if changed is None:\n            raise ValueError(\"Expected pending payment session\")\n        return \"applied\"\n",
  "regression": [
    "        if receipt is None:\n            return \"duplicate\"\n",
    ""
  ],
  "test_scenarios": [
    [
      "First signed paid event",
      "Receipt and paid transition commit"
    ],
    [
      "Same event delivered again",
      "Duplicate result, no new state change"
    ],
    [
      "Invalid signature",
      "Route rejects before service call"
    ],
    [
      "Order mutation fails",
      "Receipt rolls back so a retry can run"
    ]
  ],
  "test_source": null,
  "test_command": "python -m pytest tests/test_paid_webhook.py"
}