[
  {
    "id": "81814d6f-49fc-409f-b0a0-50ee3c08893e",
    "sort_order": 0,
    "rubric_text": "In file `dock_schedule.xlsx`, APPT-20260520-001 must have Status='Arrived', Actual_Arrival_Time='07:02' (or equivalent), Actual_Departure_Time blank; and APPT-20260520-002 must retain Status='Scheduled' and Actual_Arrival_Time blank.",
    "verifier_code": "from pathlib import Path\nimport datetime\nimport openpyxl\n\ndef verify(workspace_path, external_services_path=None):\n    xlsx_files = list(Path(workspace_path).glob('dock_schedule.xlsx'))\n    if not xlsx_files:\n        xlsx_files = list(Path(workspace_path).glob('*dock*schedule*.xlsx'))\n    if not xlsx_files:\n        return {'pass': False, 'score': 0.0, 'feedback': 'dock_schedule.xlsx not found in workspace'}\n\n    wb = openpyxl.load_workbook(xlsx_files[0])\n    ws = wb.active\n\n    # Find headers\n    header_row = None\n    headers = {}\n    for row in ws.iter_rows():\n        for cell in row:\n            val = str(cell.value or '').strip().lower().replace(' ', '_')\n            if 'appt' in val or val in ('appt_id', 'appointment_id', 'apptid'):\n                header_row = cell.row\n                headers[val] = cell.column\n        if header_row:\n            for cell in ws[header_row]:\n                if cell.value:\n                    headers[str(cell.value).strip().lower().replace(' ', '_')] = cell.column\n            break\n\n    if not header_row:\n        return {'pass': False, 'score': 0.0, 'feedback': 'Could not find header row in dock_schedule.xlsx'}\n\n    # Prefer exact match, fall back to substring\n    def find_col(exact, fallback=None):\n        if exact in headers:\n            return headers[exact]\n        if fallback:\n            for k, v in headers.items():\n                if fallback in k:\n                    return v\n        return None\n\n    appt_col      = find_col('appointment_id', 'appt')\n    status_col    = find_col('status')\n    arrival_col   = find_col('actual_arrival_time', 'actual_arrival')\n    departure_col = find_col('actual_departure_time', 'actual_departure')\n\n    if not appt_col:\n        return {'pass': False, 'score': 0.0, 'feedback': 'Could not find appointment ID column in dock_schedule.xlsx'}\n\n    appt_001 = None\n    appt_002 = None\n    for row in ws.iter_rows(min_row=header_row + 1):\n        appt_val = str(row[appt_col - 1].value or '').strip()\n        if appt_val == 'APPT-20260520-001':\n            appt_001 = row\n        elif appt_val == 'APPT-20260520-002':\n            appt_002 = row\n\n    issues = []\n\n    # Check APPT-20260520-001\n    if appt_001 is None:\n        issues.append('APPT-20260520-001 not found in dock_schedule.xlsx')\n    else:\n        status_val = str(appt_001[status_col - 1].value or '').strip() if status_col else ''\n        if status_val.lower() != 'arrived':\n            issues.append(f'APPT-20260520-001 Status is \"{status_val}\", expected \"Arrived\"')\n\n        if arrival_col:\n            arrival_val = appt_001[arrival_col - 1].value\n            arrival_str = str(arrival_val or '').strip()\n            if isinstance(arrival_val, (datetime.time, datetime.datetime)):\n                if not (arrival_val.hour == 7 and arrival_val.minute == 2):\n                    issues.append(f'APPT-20260520-001 Actual_Arrival_Time is {arrival_val}, expected 07:02')\n            elif arrival_str in ('', 'None', 'none'):\n                issues.append('APPT-20260520-001 Actual_Arrival_Time is blank, expected 07:02')\n            elif '7:02' not in arrival_str and '07:02' not in arrival_str:\n                issues.append(f'APPT-20260520-001 Actual_Arrival_Time is \"{arrival_str}\", expected 07:02')\n\n        if departure_col:\n            departure_val = appt_001[departure_col - 1].value\n            if departure_val is not None and str(departure_val).strip() not in ('', 'None', 'none'):\n                issues.append(f'APPT-20260520-001 Actual_Departure_Time should be blank but is \"{departure_val}\"')\n\n    # Check APPT-20260520-002\n    if appt_002 is None:\n        issues.append('APPT-20260520-002 not found in dock_schedule.xlsx')\n    else:\n        status_val = str(appt_002[status_col - 1].value or '').strip() if status_col else ''\n        if status_val.lower() != 'scheduled':\n            issues.append(f'APPT-20260520-002 Status is \"{status_val}\", expected \"Scheduled\"')\n\n        if arrival_col:\n            arrival_val = appt_002[arrival_col - 1].value\n            if arrival_val is not None and str(arrival_val).strip() not in ('', 'None', 'none'):\n                issues.append(f'APPT-20260520-002 Actual_Arrival_Time should be blank but is \"{arrival_val}\"')\n\n    if issues:\n        return {'pass': False, 'score': 0.0, 'feedback': 'dock_schedule.xlsx issues: ' + '; '.join(issues)}\n\n    return {'pass': True, 'score': 1.0, 'feedback': 'dock_schedule.xlsx: APPT-20260520-001 has Status=Arrived, Actual_Arrival_Time=07:02, Departure blank; APPT-20260520-002 has Status=Scheduled, Arrival blank. All correct.'}",
    "criterion_type": "expected_output"
  },
  {
    "id": "f76a0ee6-51ab-4a59-98bd-f83f9d53ff91",
    "sort_order": 1,
    "rubric_text": "In file `receiving_log.xlsx`, a row for REC-20260520-001 must exist with: Receipt_ID=REC-20260520-001, Arrival_Timestamp=05/20/2026 07:02, Dock_Door=Dock 2, Supplier_ID=SUP-0155, Carrier_Name=XPO Logistics, PO_Number=MER-PO-104903, PO_Line=002, SKU=FS-10091-B1, Safety_Critical=Y, Qty_Ordered=1800, Qty_Claimed_On_Slip=1600, Status=Awaiting Count, and Coordinator_Initials populated.",
    "verifier_code": "from pathlib import Path\nimport openpyxl\nimport datetime\n\ndef verify(workspace_path, external_services_path=None):\n    xlsx_files = list(Path(workspace_path).glob('receiving_log.xlsx'))\n    if not xlsx_files:\n        xlsx_files = list(Path(workspace_path).glob('*receiving*log*.xlsx'))\n    if not xlsx_files:\n        return {'pass': False, 'score': 0.0, 'feedback': 'receiving_log.xlsx not found in workspace'}\n\n    wb = openpyxl.load_workbook(xlsx_files[0])\n    ws = wb.active\n\n    # Find headers\n    header_row = None\n    headers = {}\n    for row in ws.iter_rows():\n        for cell in row:\n            if cell.value and 'receipt' in str(cell.value).lower():\n                header_row = cell.row\n                break\n        if header_row:\n            for cell in ws[header_row]:\n                if cell.value:\n                    key = str(cell.value).strip().lower().replace(' ', '_')\n                    headers[key] = cell.column\n            break\n\n    if not header_row:\n        return {'pass': False, 'score': 0.0, 'feedback': 'Could not find header row in receiving_log.xlsx'}\n\n    # Exact match first, then substring fallback\n    def find_col(*keywords):\n        for kw in keywords:\n            kw_lower = kw.lower()\n            if kw_lower in headers:\n                return headers[kw_lower]\n        for kw in keywords:\n            kw_lower = kw.lower()\n            for k, v in headers.items():\n                if kw_lower in k:\n                    return v\n        return None\n\n    receipt_col     = find_col('receipt_id')\n    arrival_col     = find_col('arrival_timestamp', 'arrival_time', 'arrival')\n    dock_col        = find_col('dock_door', 'dock')\n    supplier_col    = find_col('supplier_id')\n    carrier_col     = find_col('carrier_name', 'carrier')\n    coord_col       = find_col('coordinator_initials', 'coordinator', 'initials')\n    po_num_col      = find_col('po_number', 'po_num')\n    po_line_col     = find_col('po_line')\n    sku_col         = find_col('sku')\n    safety_col      = find_col('safety_critical', 'safety')\n    qty_ordered_col = find_col('qty_ordered', 'quantity_ordered')\n    qty_slip_col    = find_col('qty_claimed_on_slip', 'qty_claimed', 'claimed_on_slip')\n    status_col      = find_col('status')\n\n    target_row = None\n    for row in ws.iter_rows(min_row=header_row + 1):\n        if receipt_col and receipt_col <= len(row):\n            val = str(row[receipt_col - 1].value or '').strip()\n            if val == 'REC-20260520-001':\n                target_row = row\n                break\n\n    if target_row is None:\n        return {'pass': False, 'score': 0.0, 'feedback': 'Row REC-20260520-001 not found in receiving_log.xlsx'}\n\n    def get_val(col):\n        if col and col <= len(target_row):\n            return target_row[col - 1].value\n        return None\n\n    issues = []\n\n    # Arrival timestamp: 05/20/2026 07:02\n    arrival_val = get_val(arrival_col)\n    if arrival_val is None:\n        issues.append('Arrival_Timestamp is blank')\n    else:\n        arrival_str = str(arrival_val).strip()\n        if isinstance(arrival_val, datetime.datetime):\n            if not (arrival_val.month == 5 and arrival_val.day == 20 and arrival_val.year == 2026\n                    and arrival_val.hour == 7 and arrival_val.minute == 2):\n                issues.append(f'Arrival_Timestamp is {arrival_val}, expected 05/20/2026 07:02')\n        else:\n            if '05/20/2026' not in arrival_str and '2026-05-20' not in arrival_str:\n                issues.append(f'Arrival_Timestamp does not contain 05/20/2026: got \"{arrival_str}\"')\n            if '7:02' not in arrival_str and '07:02' not in arrival_str:\n                issues.append(f'Arrival_Timestamp does not contain 07:02: got \"{arrival_str}\"')\n\n    # Dock Door\n    dock_val = str(get_val(dock_col) or '').strip()\n    if 'dock 2' not in dock_val.lower() and 'dock2' not in dock_val.lower().replace(' ', ''):\n        issues.append(f'Dock_Door is \"{dock_val}\", expected Dock 2')\n\n    # Supplier ID\n    sup_val = str(get_val(supplier_col) or '').strip()\n    if sup_val != 'SUP-0155':\n        issues.append(f'Supplier_ID is \"{sup_val}\", expected SUP-0155')\n\n    # Carrier Name\n    carrier_val = str(get_val(carrier_col) or '').strip()\n    if 'xpo' not in carrier_val.lower():\n        issues.append(f'Carrier_Name is \"{carrier_val}\", expected XPO Logistics')\n\n    # Coordinator Initials - just check it's populated\n    coord_val = get_val(coord_col)\n    if coord_val is None or str(coord_val).strip() == '':\n        issues.append('Coordinator_Initials is blank, expected to be populated')\n\n    # PO Number\n    po_val = str(get_val(po_num_col) or '').strip()\n    if po_val != 'MER-PO-104903':\n        issues.append(f'PO_Number is \"{po_val}\", expected MER-PO-104903')\n\n    # PO Line\n    po_line_val = str(get_val(po_line_col) or '').strip()\n    if po_line_val not in ('2', '002', '2.0'):\n        issues.append(f'PO_Line is \"{po_line_val}\", expected 002')\n\n    # SKU\n    sku_val = str(get_val(sku_col) or '').strip()\n    if sku_val != 'FS-10091-B1':\n        issues.append(f'SKU is \"{sku_val}\", expected FS-10091-B1')\n\n    # Safety Critical\n    safety_val = str(get_val(safety_col) or '').strip().upper()\n    if safety_val not in ('Y', 'YES', 'TRUE', '1'):\n        issues.append(f'Safety_Critical is \"{safety_val}\", expected Y')\n\n    # Qty Ordered\n    qty_ord_val = get_val(qty_ordered_col)\n    try:\n        if abs(float(str(qty_ord_val or '0').replace(',', '')) - 1800) > 1:\n            issues.append(f'Qty_Ordered is {qty_ord_val}, expected 1800')\n    except (ValueError, TypeError):\n        issues.append(f'Qty_Ordered is \"{qty_ord_val}\", expected 1800')\n\n    # Qty Claimed On Slip\n    qty_slip_val = get_val(qty_slip_col)\n    try:\n        if abs(float(str(qty_slip_val or '0').replace(',', '')) - 1600) > 1:\n            issues.append(f'Qty_Claimed_On_Slip is {qty_slip_val}, expected 1600')\n    except (ValueError, TypeError):\n        issues.append(f'Qty_Claimed_On_Slip is \"{qty_slip_val}\", expected 1600')\n\n    # Status\n    status_val = str(get_val(status_col) or '').strip().lower()\n    if 'awaiting' not in status_val and 'count' not in status_val:\n        issues.append(f'Status is \"{status_val}\", expected \"Awaiting Count\"')\n\n    if issues:\n        return {'pass': False, 'score': 0.0, 'feedback': 'REC-20260520-001 issues: ' + '; '.join(issues)}\n\n    return {'pass': True, 'score': 1.0, 'feedback': 'REC-20260520-001 row found with all required fields correctly populated.'}",
    "criterion_type": "expected_output"
  },
  {
    "id": "eb8d673a-4415-41f2-9ff5-953fed61835d",
    "sort_order": 2,
    "rubric_text": "In file receiving_log.xlsx, the Notes field for REC-20260520-001 must contain the partial fulfillment notation: Partial PO fulfillment: this shipment covers PO line(s) 002.",
    "verifier_code": "from pathlib import Path\nimport re\nimport openpyxl\n\ndef verify(workspace_path, external_services_path=None):\n    # Find the receiving log file - be generous with naming\n    xlsx_files = list(Path(workspace_path).glob('receiving_log.xlsx'))\n    if not xlsx_files:\n        xlsx_files = list(Path(workspace_path).glob('*receiving*log*.xlsx'))\n    if not xlsx_files:\n        xlsx_files = list(Path(workspace_path).glob('**/receiving_log.xlsx'))\n    if not xlsx_files:\n        xlsx_files = list(Path(workspace_path).glob('**/*receiving*log*.xlsx'))\n    if not xlsx_files:\n        return {'pass': False, 'score': 0.0, 'feedback': 'receiving_log.xlsx not found in workspace'}\n\n    wb = openpyxl.load_workbook(xlsx_files[0])\n    ws = wb.active\n\n    # Find header row\n    header_row = None\n    headers = {}\n    for row in ws.iter_rows():\n        for cell in row:\n            if cell.value and any(kw in str(cell.value).lower() for kw in ['receipt', 'notes', 'id', 'record']):\n                header_row = cell.row\n                break\n        if header_row:\n            for cell in ws[header_row]:\n                if cell.value:\n                    key = str(cell.value).strip().lower().replace(' ', '_')\n                    headers[key] = cell.column\n            break\n\n    if not header_row:\n        return {'pass': False, 'score': 0.0, 'feedback': 'Could not find header row in receiving_log.xlsx'}\n\n    # Helper to find columns loosely\n    def find_col(*keywords):\n        for kw in keywords:\n            if kw.lower() in headers:\n                return headers[kw.lower()]\n        for kw in keywords:\n            for k, v in headers.items():\n                if kw.lower() in k:\n                    return v\n        return None\n\n    receipt_col = find_col('receipt_id', 'receipt', 'rec_id', 'id')\n    notes_col = find_col('notes', 'note', 'comments', 'comment', 'remarks')\n\n    if not receipt_col:\n        return {'pass': False, 'score': 0.0, 'feedback': f'Receipt_ID column not found in receiving_log.xlsx. Headers found: {headers}'}\n\n    # Find the target row\n    target_row = None\n    for row in ws.iter_rows(min_row=header_row + 1):\n        if receipt_col <= len(row):\n            val = str(row[receipt_col - 1].value or '').strip()\n            if val == 'REC-20260520-001':\n                target_row = row\n                break\n\n    if target_row is None:\n        # Also try searching all cells for the receipt ID\n        all_receipt_ids = []\n        for row in ws.iter_rows(min_row=header_row + 1):\n            if receipt_col <= len(row):\n                all_receipt_ids.append(str(row[receipt_col - 1].value or '').strip())\n        return {'pass': False, 'score': 0.0, 'feedback': f'REC-20260520-001 not found in receiving_log.xlsx. Receipt IDs found: {all_receipt_ids[:20]}'}\n\n    # Extract notes text\n    notes_text = ''\n    if notes_col and notes_col <= len(target_row):\n        notes_text = str(target_row[notes_col - 1].value or '')\n    else:\n        # Fallback: join all cell values in the row\n        notes_text = ' '.join(str(c.value or '') for c in target_row)\n\n    notes_lower = notes_text.lower()\n    issues = []\n\n    # The rubric requires: \"Partial PO fulfillment: this shipment covers PO line(s) 002\"\n    # We check for the key components loosely:\n\n    # 1. Must mention partial fulfillment\n    if not re.search(r'partial', notes_lower):\n        issues.append('Notes does not mention \"partial\" fulfillment')\n\n    # 2. Must reference PO line(s) 002 / line 002 / line 2\n    if not (re.search(r'line\\(?s?\\)?\\s*0*2\\b', notes_lower) or re.search(r'\\bline\\s*0*2\\b', notes_lower) or re.search(r'\\b0*2\\b', notes_lower)):\n        issues.append('Notes does not mention PO line 002')\n\n    # 3. Must indicate this shipment covers those lines\n    if not re.search(r'cover|shipment', notes_lower):\n        issues.append('Notes does not indicate shipment coverage')\n\n    # 4. Must mention PO fulfillment context\n    if not re.search(r'po|fulfil', notes_lower):\n        issues.append('Notes does not reference PO fulfillment')\n\n    if issues:\n        return {\n            'pass': False,\n            'score': 0.0,\n            'feedback': f'REC-20260520-001 Notes partial fulfillment issues: {\"; \".join(issues)}. Notes found: \"{notes_text[:300]}\"'\n        }\n\n    return {\n        'pass': True,\n        'score': 1.0,\n        'feedback': f'REC-20260520-001 Notes contains the required partial PO fulfillment notation for PO line(s) 002. Notes: \"{notes_text[:200]}\"'\n    }\n",
    "criterion_type": "expected_output"
  },
  {
    "id": "eba078e4-3663-46ef-a631-2b0c08cd4cb0",
    "sort_order": 3,
    "rubric_text": "In file `receiving_log.xlsx`, the disposition columns (Qty_Received, Variance_Units, Variance_Pct, Disposition) for REC-20260520-001 must remain blank.",
    "verifier_code": "from pathlib import Path\nimport openpyxl\n\ndef verify(workspace_path, external_services_path=None):\n    xlsx_files = list(Path(workspace_path).glob('receiving_log.xlsx'))\n    if not xlsx_files:\n        xlsx_files = list(Path(workspace_path).glob('*receiving*log*.xlsx'))\n    if not xlsx_files:\n        return {'pass': False, 'score': 0.0, 'feedback': 'receiving_log.xlsx not found in workspace'}\n\n    wb = openpyxl.load_workbook(xlsx_files[0])\n    ws = wb.active\n\n    header_row = None\n    headers = {}\n    for row in ws.iter_rows():\n        for cell in row:\n            if cell.value and 'receipt' in str(cell.value).lower():\n                header_row = cell.row\n                break\n        if header_row:\n            for cell in ws[header_row]:\n                if cell.value:\n                    key = str(cell.value).strip().lower().replace(' ', '_')\n                    headers[key] = cell.column\n            break\n\n    if not header_row:\n        return {'pass': False, 'score': 0.0, 'feedback': 'Could not find header row in receiving_log.xlsx'}\n\n    receipt_col = None\n    for k, v in headers.items():\n        if 'receipt_id' in k or k == 'receipt':\n            receipt_col = v\n            break\n\n    if not receipt_col:\n        return {'pass': False, 'score': 0.0, 'feedback': 'Receipt_ID column not found'}\n\n    # 'disposition' is matched exactly to avoid catching 'disposition_timestamp'\n    # or any other column that merely contains the substring\n    EXACT_COLS = {'disposition'}\n    SUBSTR_COLS = ('qty_received', 'variance_unit', 'variance_pct', 'variance_percent')\n\n    disp_cols = {}\n    for k, v in headers.items():\n        if k in EXACT_COLS or any(kw in k for kw in SUBSTR_COLS):\n            disp_cols[k] = v\n\n    # Verify all four required columns were found\n    REQUIRED = ('qty_received', 'variance_unit', 'variance_pct', 'disposition')\n    missing = []\n    for kw in REQUIRED:\n        if kw == 'disposition':\n            if kw not in disp_cols:\n                missing.append(kw)\n        else:\n            if not any(kw in k for k in disp_cols):\n                missing.append(kw)\n    if missing:\n        return {'pass': False, 'score': 0.0, 'feedback': f'Could not find expected disposition columns in headers: {missing}. Found headers: {list(headers.keys())}'}\n\n    target_row = None\n    for row in ws.iter_rows(min_row=header_row + 1):\n        if receipt_col <= len(row):\n            val = str(row[receipt_col - 1].value or '').strip()\n            if val == 'REC-20260520-001':\n                target_row = row\n                break\n\n    if target_row is None:\n        return {'pass': False, 'score': 0.0, 'feedback': 'REC-20260520-001 not found in receiving_log.xlsx'}\n\n    issues = []\n    for col_name, col_idx in disp_cols.items():\n        if col_idx <= len(target_row):\n            val = target_row[col_idx - 1].value\n            if val is not None and str(val).strip() not in ('', 'None', 'none'):\n                issues.append(f'{col_name} is \"{val}\", expected blank')\n\n    if issues:\n        return {'pass': False, 'score': 0.0, 'feedback': 'Disposition columns should be blank for REC-20260520-001: ' + '; '.join(issues)}\n\n    return {'pass': True, 'score': 1.0, 'feedback': f'Disposition columns (Qty_Received, Variance_Units, Variance_Pct, Disposition) are all blank for REC-20260520-001. Checked columns: {list(disp_cols.keys())}'}",
    "criterion_type": "expected_output"
  },
  {
    "id": "afe8873d-4317-4aef-951e-1eae0c7a375f",
    "sort_order": 4,
    "rubric_text": "In file `receiving_log.xlsx`, no row must exist with Receipt_ID=REC-20260520-002, Supplier_ID=SUP-0374, or any reference to Meridian Packaging Supply (since the truck has not arrived).",
    "verifier_code": "from pathlib import Path\nimport openpyxl\n\ndef verify(workspace_path, external_services_path=None):\n    xlsx_files = list(Path(workspace_path).glob('receiving_log.xlsx'))\n    if not xlsx_files:\n        xlsx_files = list(Path(workspace_path).glob('*receiving*log*.xlsx'))\n    if not xlsx_files:\n        return {'pass': False, 'score': 0.0, 'feedback': 'receiving_log.xlsx not found in workspace'}\n\n    wb = openpyxl.load_workbook(xlsx_files[0])\n    ws = wb.active\n\n    # Find headers to identify receipt_id and arrival columns\n    header_row = None\n    headers = {}\n    for row in ws.iter_rows():\n        for cell in row:\n            if cell.value and 'receipt' in str(cell.value).lower():\n                header_row = cell.row\n                break\n        if header_row:\n            for cell in ws[header_row]:\n                if cell.value:\n                    key = str(cell.value).strip().lower().replace(' ', '_')\n                    headers[key] = cell.column\n            break\n\n    def find_col(*keywords):\n        for kw in keywords:\n            if kw.lower() in headers:\n                return headers[kw.lower()]\n        for kw in keywords:\n            for k, v in headers.items():\n                if kw.lower() in k:\n                    return v\n        return None\n\n    receipt_col  = find_col('receipt_id', 'receipt')\n    arrival_col  = find_col('arrival_timestamp', 'arrival_time', 'arrival')\n    supplier_col = find_col('supplier_id')\n\n    violations = []\n\n    for row in ws.iter_rows(min_row=(header_row + 1) if header_row else 2):\n        row_vals = {col: str(cell.value or '').strip() for col, cell in enumerate(row, start=1)}\n        full_text = ' '.join(row_vals.values())\n\n        receipt_val  = row_vals.get(receipt_col, '')  if receipt_col  else ''\n        arrival_val  = row_vals.get(arrival_col, '')  if arrival_col  else ''\n        supplier_val = row_vals.get(supplier_col, '') if supplier_col else ''\n\n        # REC-20260520-002 should never exist regardless of date\n        if receipt_val == 'REC-20260520-002':\n            violations.append(f'Row {row[0].row}: Receipt_ID REC-20260520-002 found — Meridian truck has not arrived')\n\n        # SUP-0374 or Meridian Packaging only flagged if the row is dated 05/20/2026 or later\n        is_may20_or_later = '05/20/2026' in arrival_val or '2026-05-20' in arrival_val \\\n                            or any(f'05/{d}/2026' in arrival_val for d in range(20, 32)) \\\n                            or any(f'2026-05-{d:02d}' in arrival_val for d in range(20, 32))\n\n        if is_may20_or_later:\n            if supplier_val == 'SUP-0374':\n                violations.append(f'Row {row[0].row}: SUP-0374 (Meridian) found with arrival date {arrival_val} — truck has not arrived')\n            if 'meridian packaging' in full_text.lower():\n                violations.append(f'Row {row[0].row}: \"Meridian Packaging\" reference found with arrival date {arrival_val}')\n\n    if violations:\n        return {'pass': False, 'score': 0.0, 'feedback': 'receiving_log.xlsx contains entries that should not exist: ' + '; '.join(violations)}\n\n    return {'pass': True, 'score': 1.0, 'feedback': 'No invalid Meridian Packaging Supply entries found in receiving_log.xlsx (REC-20260520-002 absent; no SUP-0374 or Meridian Packaging rows dated 05/20/2026 or later). Correct.'}",
    "criterion_type": "incorrect_behavior"
  },
  {
    "id": "cd7781ef-2bf7-4425-9693-bba7cc45de35",
    "sort_order": 5,
    "rubric_text": "In `slack_data.json` (external services), no message must exist in #receiving-dock (channel C001) with text indicating APPT-20260520-002 or Meridian Packaging Supply has arrived.",
    "verifier_code": "from pathlib import Path\nimport json\n\ndef verify(workspace_path, external_services_path=None):\n    slack_path = None\n    for base in [external_services_path, workspace_path]:\n        if base is None:\n            continue\n        p = Path(base) / 'slack_data.json'\n        if p.exists():\n            slack_path = p\n            break\n\n    if slack_path is None:\n        return {'pass': False, 'score': 0.0, 'feedback': 'slack_data.json not found'}\n\n    with open(slack_path, 'r') as f:\n        data = json.load(f)\n\n    messages = data.get('messages', {})\n\n    if 'C001' not in messages:\n        return {'pass': False, 'score': 0.0, 'feedback': 'Channel C001 (#receiving-dock) not found in slack_data.json messages'}\n\n    c001_messages = messages.get('C001', [])\n\n    violations = []\n    for msg in c001_messages:\n        text = str(msg.get('text', '')).strip()\n        text_lower = text.lower()\n        if 'appt-20260520-002' in text_lower and ('arrival' in text_lower or 'arrived' in text_lower or 'cleared' in text_lower):\n            violations.append(f'Found message about APPT-20260520-002 arrival: \"{text[:200]}\"')\n        if 'meridian' in text_lower and ('arrival' in text_lower or 'arrived' in text_lower or 'cleared' in text_lower):\n            violations.append(f'Found message about Meridian arrival: \"{text[:200]}\"')\n\n    if violations:\n        return {'pass': False, 'score': 0.0, 'feedback': 'Found arrival messages for APPT-20260520-002/Meridian that should not exist: ' + '; '.join(violations)}\n\n    return {'pass': True, 'score': 1.0, 'feedback': 'No arrival message found for APPT-20260520-002 or Meridian Packaging Supply in #receiving-dock. Correct.'}",
    "criterion_type": "incorrect_behavior"
  },
  {
    "id": "a0d732c3-82a8-4f65-acaf-9f00f51b0b3f",
    "sort_order": 6,
    "rubric_text": "In `slack_data.json` (external services), no DM channel (is_im: true or is_mpim: true) must contain any message about an unknown PO for Meridian Packaging Supply or PO number MER-PO-105004.",
    "verifier_code": "from pathlib import Path\nimport json\n\ndef verify(workspace_path, external_services_path=None):\n    slack_path = None\n    for base in [external_services_path, workspace_path]:\n        if base is None:\n            continue\n        p = Path(base) / 'slack_data.json'\n        if p.exists():\n            slack_path = p\n            break\n\n    if slack_path is None:\n        return {'pass': False, 'score': 0.0, 'feedback': 'slack_data.json not found'}\n\n    with open(slack_path, 'r') as f:\n        data = json.load(f)\n\n    channels = data.get('channels', {})\n    messages = data.get('messages', {})\n\n    # channels may be a dict {id: {...}} or a list [{id: ..., ...}]\n    if isinstance(channels, list):\n        dm_channel_ids = {\n            ch['id'] for ch in channels\n            if isinstance(ch, dict) and (ch.get('is_im', False) or ch.get('is_mpim', False))\n        }\n    else:\n        dm_channel_ids = {\n            cid for cid, ch in channels.items()\n            if isinstance(ch, dict) and (ch.get('is_im', False) or ch.get('is_mpim', False))\n        }\n\n    violations = []\n\n    for cid in dm_channel_ids:\n        for msg in messages.get(cid, []):\n            text = str(msg.get('text', ''))\n            text_lower = text.lower()\n            if 'mer-po-105004' in text_lower:\n                violations.append(f'DM channel {cid} contains MER-PO-105004: \"{text[:200]}\"')\n            elif 'meridian' in text_lower and ('unknown' in text_lower or 'po' in text_lower):\n                violations.append(f'DM channel {cid} contains Meridian/PO reference: \"{text[:200]}\"')\n\n    if violations:\n        return {'pass': False, 'score': 0.0, 'feedback': 'DM channels contain Meridian/MER-PO-105004 messages that should not exist: ' + '; '.join(violations)}\n\n    return {'pass': True, 'score': 1.0, 'feedback': f'No DM channel messages found referencing Meridian Packaging Supply or MER-PO-105004. DM channels checked: {dm_channel_ids or \"none (no DM channels exist)\"}. Correct.'}",
    "criterion_type": "incorrect_behavior"
  },
  {
    "id": "69a20af9-2324-49f6-b9fd-843295ae45d2",
    "sort_order": 7,
    "rubric_text": "In `slack_data.json` (external services), a message must exist in #receiving-dock (channel C001) from U001 or U_MOCK_BOT with text matching: 'ARRIVAL ON TIME: APPT-20260520-001, Ritter Fastener Group, Dock 2, PO #MER-PO-104903. Cleared to unload.'",
    "verifier_code": "from pathlib import Path\nimport json\n\ndef verify(workspace_path, external_services_path=None):\n    slack_path = None\n    for base in [external_services_path, workspace_path]:\n        if base is None:\n            continue\n        p = Path(base) / 'slack_data.json'\n        if p.exists():\n            slack_path = p\n            break\n\n    if slack_path is None:\n        return {'pass': False, 'score': 0.0, 'feedback': 'slack_data.json not found'}\n\n    with open(slack_path, 'r') as f:\n        data = json.load(f)\n\n    messages = data.get('messages', {})\n\n    if 'C001' not in messages:\n        return {'pass': False, 'score': 0.0, 'feedback': 'Channel C001 (#receiving-dock) not found in slack_data.json messages'}\n\n    c001_messages = messages.get('C001', [])\n\n    required_components = [\n        'arrival on time',\n        'appt-20260520-001',\n        'ritter fastener',\n        'dock 2',\n        'mer-po-104903',\n        'cleared to unload'\n    ]\n\n    found_msg = None\n    wrong_user_msg = None\n\n    for msg in c001_messages:\n        user = str(msg.get('user', '')).strip()\n        text = str(msg.get('text', '')).strip()\n        text_lower = text.lower()\n\n        components_ok = all(comp in text_lower for comp in required_components)\n        user_ok = user in ('U001', 'U_MOCK_BOT') or 'mock_bot' in user.lower()\n\n        if components_ok and user_ok:\n            found_msg = text\n            break\n        elif components_ok and not user_ok:\n            wrong_user_msg = (text, user)\n\n    if found_msg:\n        return {'pass': True, 'score': 1.0, 'feedback': f'Found arrival confirmation message in #receiving-dock: \"{found_msg[:300]}\"'}\n\n    if wrong_user_msg:\n        return {'pass': False, 'score': 0.0, 'feedback': f'Arrival confirmation message found but posted by wrong user \"{wrong_user_msg[1]}\" (expected U001 or U_MOCK_BOT): \"{wrong_user_msg[0][:200]}\"'}\n\n    sample = [msg.get('text', '')[:100] for msg in c001_messages[-5:]] if c001_messages else []\n    return {'pass': False, 'score': 0.0, 'feedback': f'No arrival confirmation message for APPT-20260520-001 found in #receiving-dock (C001). Required components: {required_components}. Last messages: {sample}'}",
    "criterion_type": "expected_output"
  },
  {
    "id": "9b775093-1ddb-43f3-a934-7617a75a2a87",
    "sort_order": 8,
    "rubric_text": "In file `open_pos.xlsx`, the row for MER-PO-104903 Line 002 must be entirely unmodified with all original values: Supplier_ID=SUP-0155, Supplier_Name=Ritter Fastener Group, SKU=FS-10091-B1, Qty_Ordered=1800, Unit_Price=3.20, Safety_Critical=Y, Receipt_Status=Open, and Notes blank.",
    "verifier_code": "from pathlib import Path\nimport openpyxl\n\ndef verify(workspace_path, external_services_path=None):\n    xlsx_files = list(Path(workspace_path).glob('open_pos.xlsx'))\n    if not xlsx_files:\n        xlsx_files = list(Path(workspace_path).glob('*open*po*.xlsx')) + list(Path(workspace_path).glob('*po*.xlsx'))\n    if not xlsx_files:\n        return {'pass': False, 'score': 0.0, 'feedback': 'open_pos.xlsx not found in workspace'}\n\n    wb = openpyxl.load_workbook(xlsx_files[0])\n    ws = wb.active\n\n    # Find headers\n    header_row = None\n    headers = {}\n    for row in ws.iter_rows():\n        for cell in row:\n            if cell.value and 'po_number' in str(cell.value).lower().replace(' ', '_'):\n                header_row = cell.row\n                break\n        if header_row:\n            for cell in ws[header_row]:\n                if cell.value:\n                    key = str(cell.value).strip().lower().replace(' ', '_')\n                    headers[key] = cell.column\n            break\n\n    if not header_row:\n        return {'pass': False, 'score': 0.0, 'feedback': 'Could not find header row in open_pos.xlsx'}\n\n    # Exact match first, then substring fallback\n    def find_col(*keywords):\n        for kw in keywords:\n            if kw.lower() in headers:\n                return headers[kw.lower()]\n        for kw in keywords:\n            for k, v in headers.items():\n                if kw.lower() in k:\n                    return v\n        return None\n\n    po_col   = find_col('po_number')\n    line_col = find_col('po_line')\n\n    # Find the target row\n    target_row = None\n    for row in ws.iter_rows(min_row=header_row + 1):\n        po_val   = str(row[po_col - 1].value or '').strip() if po_col else ''\n        line_val = str(row[line_col - 1].value or '').strip() if line_col else ''\n        if po_val == 'MER-PO-104903' and line_val in ('2', '002', '2.0'):\n            target_row = row\n            break\n\n    if target_row is None:\n        return {'pass': False, 'score': 0.0, 'feedback': 'Row MER-PO-104903 Line 002 not found in open_pos.xlsx'}\n\n    def get_val(col):\n        if col and col <= len(target_row):\n            return target_row[col - 1].value\n        return None\n\n    def is_blank(val):\n        return val is None or str(val).strip() in ('', 'None', 'none')\n\n    issues = []\n\n    # Expected values for all rubric-specified fields\n    checks = [\n        ('supplier_id',               'SUP-0155',                   lambda v: str(v or '').strip() == 'SUP-0155'),\n        ('supplier_name',             'Ritter Fastener Group',       lambda v: 'ritter' in str(v or '').lower() and 'fastener' in str(v or '').lower()),\n        ('sku',                       'FS-10091-B1',                 lambda v: str(v or '').strip() == 'FS-10091-B1'),\n        ('qty_ordered',               '1800',                        lambda v: abs(float(str(v or '0').replace(',', '')) - 1800) <= 1),\n        ('unit_price',                '3.20',                        lambda v: abs(float(str(v or '0').replace(',', '').replace('$', '')) - 3.20) <= 0.01),\n        ('po_date',                   '03/20/2026',                  lambda v: '03/20/2026' in str(v or '') or '2026-03-20' in str(v or '')),\n        ('requested_ship_date',       '04/28/2026',                  lambda v: '04/28/2026' in str(v or '') or '2026-04-28' in str(v or '')),\n        ('required_delivery_date',    '05/12/2026',                  lambda v: '05/12/2026' in str(v or '') or '2026-05-12' in str(v or '')),\n        ('safety_critical',           'Y',                           lambda v: str(v or '').strip().upper() in ('Y', 'YES', 'TRUE', '1')),\n        ('hazmat_flag',               'N',                           lambda v: str(v or '').strip().upper() in ('N', 'NO', 'FALSE', '0')),\n        ('dtl_flag',                  'N',                           lambda v: str(v or '').strip().upper() in ('N', 'NO', 'FALSE', '0')),\n        ('approved_revisions',        'FS-10091-B1',                 lambda v: str(v or '').strip() == 'FS-10091-B1'),\n        ('customer_doc_required',     'N',                           lambda v: str(v or '').strip().upper() in ('N', 'NO', 'FALSE', '0')),\n        ('receipt_status',            'Open',                        lambda v: str(v or '').strip().lower() == 'open'),\n    ]\n\n    blank_checks = [\n        'approved_substitutes', 'customer_substitutions', 'customer_override',\n        'new_supplier_sc_approval', 'notes'\n    ]\n\n    for col_name, expected, check_fn in checks:\n        col = find_col(col_name)\n        if col is None:\n            issues.append(f'Column \"{col_name}\" not found in headers')\n            continue\n        val = get_val(col)\n        try:\n            if not check_fn(val):\n                issues.append(f'{col_name} is \"{val}\", expected {expected}')\n        except (ValueError, TypeError):\n            issues.append(f'{col_name} is \"{val}\", expected {expected}')\n\n    for col_name in blank_checks:\n        col = find_col(col_name)\n        if col is None:\n            continue  # column may not exist — skip rather than fail\n        val = get_val(col)\n        if not is_blank(val):\n            issues.append(f'{col_name} is \"{val}\", expected blank')\n\n    if issues:\n        return {'pass': False, 'score': 0.0, 'feedback': 'MER-PO-104903 Line 002 in open_pos.xlsx has unexpected changes: ' + '; '.join(issues)}\n\n    return {'pass': True, 'score': 1.0, 'feedback': 'MER-PO-104903 Line 002 in open_pos.xlsx is unmodified with all original values correct.'}",
    "criterion_type": "expected_output"
  },
  {
    "id": "rubric_1776855404272",
    "sort_order": 9,
    "rubric_text": "In `mailbox.json`, there should be no sent emails.",
    "verifier_code": "from pathlib import Path\nimport json\n\ndef verify(workspace_path, external_services_path=None):\n    # Check mailbox.json in both workspace and external_services paths\n    mailbox_path = None\n    \n    # First try external_services_path\n    if external_services_path:\n        candidate = Path(external_services_path) / \"mailbox.json\"\n        if candidate.exists():\n            mailbox_path = candidate\n    \n    # Also check workspace_path\n    if mailbox_path is None:\n        candidate = Path(workspace_path) / \"mailbox.json\"\n        if candidate.exists():\n            mailbox_path = candidate\n    \n    if mailbox_path is None:\n        # If no mailbox.json found anywhere, that means no emails were sent.\n        # Be generous: pass.\n        return {\"pass\": True, \"score\": 1.0, \"feedback\": \"No mailbox.json found in workspace or external services path. No sent emails exist, so the condition is satisfied.\"}\n    \n    try:\n        with open(mailbox_path, 'r') as f:\n            data = json.load(f)\n    except Exception as e:\n        return {\"pass\": False, \"score\": 0.0, \"feedback\": f\"Failed to read mailbox.json at {mailbox_path}: {e}\"}\n    \n    emails = data.get(\"emails\", [])\n    \n    sent_emails = []\n    for email in emails:\n        folder = email.get(\"folder\", \"\")\n        if folder.lower() == \"sent\":\n            sent_emails.append(email)\n    \n    if len(sent_emails) == 0:\n        return {\"pass\": True, \"score\": 1.0, \"feedback\": f\"No sent emails found in mailbox.json ({mailbox_path}). Total emails in mailbox: {len(emails)}.\"}\n    else:\n        subjects = [e.get(\"subject\", \"(no subject)\") for e in sent_emails]\n        return {\"pass\": False, \"score\": 0.0, \"feedback\": f\"Found {len(sent_emails)} sent email(s) in mailbox.json, but expected none. Sent email subjects: {subjects}\"}\n",
    "criterion_type": "incorrect_behavior"
  }
]
