{
  "filename": "src/cancel.rs",
  "rule": "- name: tenant-is-in-update\n  where: \"src/cancel.rs\"\n  ensure: >-\n    The order UPDATE must include tenant_id=$2 and bind actor.tenant_id so the write is scoped to the verified tenant.",
  "corrected": "use axum::{extract::{Extension, Path, State}, http::StatusCode};\nuse sqlx::PgPool;\n\n#[derive(Clone)]\npub struct Actor { pub tenant_id: i64, pub user_id: i64 }\n\npub async fn cancel(\n    State(pool): State<PgPool>, Extension(actor): Extension<Actor>, Path(id): Path<i64>,\n) -> Result<StatusCode, StatusCode> {\n    let result = sqlx::query(\"UPDATE orders SET status='cancelled' WHERE id=$1 AND tenant_id=$2 AND owner_id=$3 AND status='pending'\")\n        .bind(id).bind(actor.tenant_id).bind(actor.user_id)\n        .execute(&pool).await.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;\n    if result.rows_affected() != 1 { return Err(StatusCode::NOT_FOUND); }\n    Ok(StatusCode::NO_CONTENT)\n}\n",
  "broken": "use axum::{extract::{Extension, Path, State}, http::StatusCode};\nuse sqlx::PgPool;\n\n#[derive(Clone)]\npub struct Actor { pub tenant_id: i64, pub user_id: i64 }\n\npub async fn cancel(\n    State(pool): State<PgPool>, Extension(actor): Extension<Actor>, Path(id): Path<i64>,\n) -> Result<StatusCode, StatusCode> {\n    let result = sqlx::query(\"UPDATE orders SET status='cancelled' WHERE id=$1 AND owner_id=$2 AND status='pending'\")\n        .bind(id).bind(actor.user_id)\n        .execute(&pool).await.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;\n    if result.rows_affected() != 1 { return Err(StatusCode::NOT_FOUND); }\n    Ok(StatusCode::NO_CONTENT)\n}\n",
  "regression": [
    "use axum::{extract::{Extension, Path, State}, http::StatusCode};\nuse sqlx::PgPool;\n\n#[derive(Clone)]\npub struct Actor { pub tenant_id: i64, pub user_id: i64 }\n\npub async fn cancel(\n    State(pool): State<PgPool>, Extension(actor): Extension<Actor>, Path(id): Path<i64>,\n) -> Result<StatusCode, StatusCode> {\n    let result = sqlx::query(\"UPDATE orders SET status='cancelled' WHERE id=$1 AND tenant_id=$2 AND owner_id=$3 AND status='pending'\")\n        .bind(id).bind(actor.tenant_id).bind(actor.user_id)\n        .execute(&pool).await.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;\n    if result.rows_affected() != 1 { return Err(StatusCode::NOT_FOUND); }\n    Ok(StatusCode::NO_CONTENT)\n}\n",
    "use axum::{extract::{Extension, Path, State}, http::StatusCode};\nuse sqlx::PgPool;\n\n#[derive(Clone)]\npub struct Actor { pub tenant_id: i64, pub user_id: i64 }\n\npub async fn cancel(\n    State(pool): State<PgPool>, Extension(actor): Extension<Actor>, Path(id): Path<i64>,\n) -> Result<StatusCode, StatusCode> {\n    let result = sqlx::query(\"UPDATE orders SET status='cancelled' WHERE id=$1 AND owner_id=$2 AND status='pending'\")\n        .bind(id).bind(actor.user_id)\n        .execute(&pool).await.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;\n    if result.rows_affected() != 1 { return Err(StatusCode::NOT_FOUND); }\n    Ok(StatusCode::NO_CONTENT)\n}\n"
  ],
  "test_scenarios": [
    [
      "Correct actor and pending row",
      "204 and one change"
    ],
    [
      "Cross-tenant order id",
      "404 and no change"
    ],
    [
      "Missing middleware identity",
      "Extractor rejection"
    ],
    [
      "Two simultaneous cancellations",
      "At most one pending update"
    ]
  ],
  "test_source": null,
  "test_command": "cargo test tenant_cancellation"
}