{
  "license": "CC BY 4.0",
  "licenseUrl": "https://creativecommons.org/licenses/by/4.0/",
  "recipe": {
    "slug": "required-field-null-rate",
    "title": "Measure Required-Field Null Rate",
    "testedWith": "Apache DataFusion 45.2.0",
    "lastReviewed": "2026-07-27"
  },
  "contract": {
    "tableName": "product_events",
    "schema": [
      {
        "name": "timestamp_utc",
        "type": "Timestamp",
        "description": "Event occurrence time."
      },
      {
        "name": "event_name",
        "type": "Utf8",
        "description": "Stable event contract name."
      },
      {
        "name": "account_id",
        "type": "Utf8",
        "description": "Account identifier required for these events."
      },
      {
        "name": "producer_version",
        "type": "Utf8",
        "description": "Application version that emitted the event."
      }
    ]
  },
  "query": "SELECT\n  event_name,\n  producer_version,\n  COUNT(*) AS events,\n  SUM(CASE\n    WHEN account_id IS NULL OR trim(account_id) = '' THEN 1\n    ELSE 0\n  END) AS missing_account_id,\n  100.0 * SUM(CASE\n    WHEN account_id IS NULL OR trim(account_id) = '' THEN 1\n    ELSE 0\n  END) / NULLIF(COUNT(*), 0) AS missing_rate_pct\nFROM product_events\nWHERE timestamp_utc >= now() - INTERVAL '24 hours'\nGROUP BY event_name, producer_version\nHAVING COUNT(*) >= 20\nORDER BY missing_rate_pct DESC, events DESC;",
  "fixtureKind": "schema-example",
  "inputRows": [
    {
      "timestamp_utc": "2026-07-28T10:00:00Z",
      "event_name": "workflow_completed",
      "account_id": "account_1",
      "producer_version": "producer_version_example_1"
    },
    {
      "timestamp_utc": "2026-07-28T11:00:00Z",
      "event_name": "workflow_completed",
      "account_id": "account_2",
      "producer_version": "producer_version_example_2"
    },
    {
      "timestamp_utc": "2026-07-28T12:00:00Z",
      "event_name": "workflow_completed",
      "account_id": "account_3",
      "producer_version": "producer_version_example_3"
    }
  ],
  "illustrativeInputRows": [
    {
      "timestamp_utc": "2026-07-28T10:00:00Z",
      "event_name": "workflow_completed",
      "account_id": "account_1",
      "producer_version": "producer_version_example_1"
    },
    {
      "timestamp_utc": "2026-07-28T11:00:00Z",
      "event_name": "workflow_completed",
      "account_id": "account_2",
      "producer_version": "producer_version_example_2"
    },
    {
      "timestamp_utc": "2026-07-28T12:00:00Z",
      "event_name": "workflow_completed",
      "account_id": "account_3",
      "producer_version": "producer_version_example_3"
    }
  ],
  "expectedOutput": {
    "columns": [
      "event_name",
      "producer_version",
      "events",
      "missing_account_id",
      "missing_rate_pct"
    ],
    "rows": [
      {
        "event_name": "dashboard_viewed",
        "producer_version": "web-1842",
        "events": 6420,
        "missing_account_id": 1187,
        "missing_rate_pct": 18.49
      },
      {
        "event_name": "query_completed",
        "producer_version": "api-918",
        "events": 3810,
        "missing_account_id": 7,
        "missing_rate_pct": 0.18
      }
    ]
  },
  "notes": [
    "The compact input rows demonstrate field names and JSON types; they are not claimed to generate the displayed aggregate by themselves.",
    "The expected output is deterministic synthetic review data for the documented output shape.",
    "Adapt time windows, thresholds, identities, and business definitions before operational use."
  ]
}