{
  "filename": "confirm.ts",
  "rule": "- name: persist-notification-before-dispatch\n  where: \"confirm.ts\"\n  ensure: >-\n    The confirm function persists a durable notification record by calling tx.insertOutbox inside the same db.transaction callback as tx.confirmOrder, before scheduling dispatchCommittedOutbox with waitUntil. Confirming the order and scheduling dispatch without inserting an outbox record violates this requirement.",
  "corrected": "import type { Context } from \"hono\";\n\ntype Transaction = { confirmOrder: (actorId:string,id:string)=>Promise<void>; insertOutbox:(key:string,id:string)=>Promise<void> };\ntype Database = { transaction:<T>(run:(tx:Transaction)=>Promise<T>)=>Promise<T> };\n\nexport async function confirm(c: Context, db: Database, actorId: string, orderId: string,\n  dispatchCommittedOutbox: () => Promise<void>) {\n  await db.transaction(async tx => {\n    await tx.confirmOrder(actorId, orderId);\n    await tx.insertOutbox(`confirmed:${orderId}`, orderId);\n  });\n  c.executionCtx.waitUntil(dispatchCommittedOutbox());\n  return c.json({status:\"confirmed\"});\n}\n",
  "broken": "import type { Context } from \"hono\";\n\ntype Transaction = { confirmOrder: (actorId:string,id:string)=>Promise<void>; insertOutbox:(key:string,id:string)=>Promise<void> };\ntype Database = { transaction:<T>(run:(tx:Transaction)=>Promise<T>)=>Promise<T> };\n\nexport async function confirm(c: Context, db: Database, actorId: string, orderId: string,\n  dispatchCommittedOutbox: () => Promise<void>) {\n  await db.transaction(async tx => {\n    await tx.confirmOrder(actorId, orderId);\n    // The notification record was accidentally removed.\n  });\n  c.executionCtx.waitUntil(dispatchCommittedOutbox());\n  return c.json({status:\"confirmed\"});\n}\n",
  "regression": [
    "    await tx.insertOutbox(`confirmed:${orderId}`, orderId);",
    "    // The notification record was accidentally removed."
  ],
  "test_scenarios": [
    [
      "Transaction completes",
      "Dispatch starts after commit"
    ],
    [
      "Transaction rejects",
      "No dispatch scheduled, no success response"
    ],
    [
      "Request process dies after commit",
      "Worker finds persisted outbox row"
    ],
    [
      "Dispatcher rejects",
      "Delivery failure recorded for retry"
    ]
  ],
  "test_source": "import { expect, test } from \"vitest\";\nimport { confirm } from \"../confirm\";\ntest(\"dispatch waits for commit\", async () => {\n  let release!: () => void;\n  const gate = new Promise<void>(resolve => { release = resolve; });\n  let dispatched = false;\n  let persisted = false;\n  const db = { transaction: async (run: any) => { await run({confirmOrder:async()=>{},insertOutbox:async()=>{persisted=true;}}); await gate; } };\n  const pending: Promise<unknown>[] = [];\n  const c = { executionCtx: {waitUntil:(promise:Promise<unknown>)=>pending.push(promise)}, json:()=>({status:200}) };\n  const result = confirm(c as any, db as any, \"owner\", \"order\", async()=>{expect(persisted).toBe(true);dispatched=true;});\n  await new Promise(resolve=>setTimeout(resolve,0));\n  expect(dispatched).toBe(false);\n  release(); await result; await Promise.all(pending);\n  expect(dispatched).toBe(true);\n  expect(persisted).toBe(true);\n});",
  "test_command": "npx vitest run tests/confirm-order.test.ts"
}