[ { "id": "562add5f-6c5a-4847-867b-95a7857b0ee0", "sort_order": 0, "rubric_text": "In file `Inbound_Receiving_Log.xlsx`, a row with manifest 2026-04-15-001 must exist with columns F-N containing (in order): 210, -10.2, -10.2, -18.7, -13.03, Tier 1, 0, 0, Exact Match; column P must be 'none'; column R must be 'P3'; column T must contain 'Open' (and may have other text as well in it); and the Lot Codes column must contain text referencing 'A-20260411-01 -- MISMATCH – manifest A-20260412-01 vs received A-20260411-01', 'A-20260410-01', and 'B-20260408-01'. Column Q must contain 'No damage'. Column S must contain 'Open'. Rounded whole-degree values are acceptable.", "verifier_code": "from pathlib import Path\nimport openpyxl\nimport re\n\ndef verify(workspace_path, external_services_path=None):\n # Search for the Inbound Receiving Log file broadly\n xlsx_files = list(Path(workspace_path).glob('**/*nbound*eceiving*og*.xlsx'))\n if not xlsx_files:\n xlsx_files = list(Path(workspace_path).glob('**/Inbound_Receiving_Log.xlsx'))\n if not xlsx_files:\n xlsx_files = list(Path(workspace_path).glob('**/inbound_receiving_log.xlsx'))\n if not xlsx_files:\n xlsx_files = [f for f in Path(workspace_path).glob('**/*.xlsx') if 'inbound' in f.name.lower() or 'receiving' in f.name.lower()]\n if not xlsx_files:\n # Try any xlsx\n xlsx_files = list(Path(workspace_path).glob('**/*.xlsx'))\n if not xlsx_files:\n return {'pass': False, 'score': 0.0, 'feedback': 'No Inbound_Receiving_Log.xlsx file found in workspace'}\n\n # Try each xlsx file to find the one with our manifest\n target_row = None\n row_num = None\n ws = None\n wb = None\n found_file = None\n\n for xlsx_file in xlsx_files:\n try:\n wb_candidate = openpyxl.load_workbook(xlsx_file, data_only=True)\n ws_candidate = wb_candidate.active\n for row in ws_candidate.iter_rows():\n for cell in row:\n if cell.value and '2026-04-15-001' in str(cell.value):\n target_row = row\n row_num = cell.row\n ws = ws_candidate\n wb = wb_candidate\n found_file = xlsx_file\n break\n if target_row:\n break\n if target_row:\n break\n except Exception:\n continue\n\n if not target_row:\n return {'pass': False, 'score': 0.0, 'feedback': 'No row found with manifest 2026-04-15-001 in any xlsx file'}\n\n def get_cell_val(col_idx):\n return ws.cell(row=row_num, column=col_idx).value\n\n # Build header map to find columns by name\n header_map = {}\n for cell in ws[1]:\n if cell.value:\n header_map[str(cell.value).strip().lower()] = cell.column\n\n # Standard column mapping: F=6, G=7, H=8, I=9, J=10, K=11, L=12, M=13, N=14, O=15, P=16, Q=17, R=18, S=19, T=20\n col_f = get_cell_val(6)\n col_g = get_cell_val(7)\n col_h = get_cell_val(8)\n col_i = get_cell_val(9)\n col_j = get_cell_val(10)\n col_k = get_cell_val(11)\n col_l = get_cell_val(12)\n col_m = get_cell_val(13)\n col_n = get_cell_val(14)\n col_p = get_cell_val(16)\n col_q = get_cell_val(17)\n col_r = get_cell_val(18)\n col_s = get_cell_val(19)\n col_t = get_cell_val(20)\n\n issues = []\n\n # Helper for numeric checks with generous tolerance\n def check_numeric(val, expected, col_name, tolerance=None):\n if tolerance is None:\n tolerance = max(abs(expected) * 0.05, 1.0)\n try:\n # Handle various string formats\n val_str = str(val).replace(',', '').strip() if val is not None else ''\n # Remove degree symbols, F/C suffixes\n val_str = re.sub(r'[°ºFCfc]', '', val_str).strip()\n if val_str == '' or val_str.lower() == 'none':\n issues.append(f'{col_name} expected ~{expected}, got {val}')\n return\n num = float(val_str)\n if abs(num - expected) > tolerance:\n issues.append(f'{col_name} expected ~{expected}, got {val} (parsed as {num})')\n except (ValueError, TypeError):\n issues.append(f'{col_name} expected ~{expected}, got {val}')\n\n # Check column F = 210 (generous: ±10)\n check_numeric(col_f, 210, 'Column F', tolerance=10)\n\n # Check column G = -10.2 (allow whole-degree rounding: -10 is fine)\n check_numeric(col_g, -10.2, 'Column G', tolerance=1.5)\n\n # Check column H = -10.2\n check_numeric(col_h, -10.2, 'Column H', tolerance=1.5)\n\n # Check column I = -18.7 (allow -19 for rounding)\n check_numeric(col_i, -18.7, 'Column I', tolerance=2.0)\n\n # Check column J = -13.03 (allow -13 for rounding)\n check_numeric(col_j, -13.03, 'Column J', tolerance=2.0)\n\n # Check column K = Tier 1\n k_str = str(col_k).lower().strip() if col_k is not None else ''\n if 'tier' not in k_str or '1' not in str(col_k):\n issues.append(f'Column K expected Tier 1, got {col_k}')\n\n # Check column L = 0\n check_numeric(col_l, 0, 'Column L', tolerance=0.5)\n\n # Check column M = 0\n check_numeric(col_m, 0, 'Column M', tolerance=0.5)\n\n # Check column N = Exact Match\n n_str = str(col_n).lower().strip() if col_n is not None else ''\n if 'exact' not in n_str or 'match' not in n_str:\n issues.append(f'Column N expected Exact Match, got {col_n}')\n\n # Check column P = none (accept none, None, n/a, empty, 0, dash, etc.)\n p_str = str(col_p).lower().strip() if col_p is not None else ''\n if p_str not in ['none', 'n/a', '', '0', '0.0', '-', 'na', 'null', 'no']:\n issues.append(f'Column P expected none, got {col_p}')\n\n # Check column Q = No damage\n q_str = str(col_q).lower().strip() if col_q is not None else ''\n if 'no damage' not in q_str and 'no dmg' not in q_str and q_str == 'none':\n pass # accept 'none' as meaning no damage\n elif 'no damage' not in q_str and 'no dmg' not in q_str and 'none' not in q_str:\n if not ('damage' in q_str and 'no' in q_str) and q_str not in ['n/a', '0', '-', 'na']:\n issues.append(f'Column Q expected \"No damage\", got {col_q}')\n\n # Check column R = P3\n r_str = str(col_r).strip().lower().replace(' ', '').replace('-', '') if col_r is not None else ''\n if 'p3' not in r_str:\n issues.append(f'Column R expected P3, got {col_r}')\n\n # Check column S contains Open\n s_str = str(col_s).lower().strip() if col_s is not None else ''\n if 'open' not in s_str:\n issues.append(f'Column S expected to contain Open, got {col_s}')\n\n # Check column T contains Open\n t_str = str(col_t).lower().strip() if col_t is not None else ''\n if 'open' not in t_str:\n issues.append(f'Column T expected to contain Open, got {col_t}')\n\n # Check lot codes - search all cells in the row\n all_row_text = ' '.join([str(cell.value or '') for cell in target_row])\n\n # Also try to find a specific \"lot\" column by header name\n lot_codes_val = ''\n for hdr_name, hdr_col in header_map.items():\n if 'lot' in hdr_name:\n lot_val = ws.cell(row=row_num, column=hdr_col).value\n if lot_val:\n lot_codes_val += ' ' + str(lot_val)\n\n # Also check column O (15) as a common lot codes location\n col_o = get_cell_val(15)\n if col_o:\n lot_codes_val += ' ' + str(col_o)\n\n search_text = all_row_text + ' ' + lot_codes_val\n\n # Check for A-20260411-01 with mismatch info\n has_20260411 = 'A-20260411-01' in search_text or '20260411' in search_text\n if not has_20260411:\n issues.append('Lot codes missing A-20260411-01 reference')\n else:\n # Check mismatch text\n if 'mismatch' not in search_text.lower():\n issues.append('Lot codes missing MISMATCH notation for lot code discrepancy')\n if 'A-20260412-01' not in search_text and '20260412' not in search_text:\n issues.append('Lot codes missing manifest lot A-20260412-01 reference in mismatch')\n\n # Check for A-20260410-01\n if 'A-20260410-01' not in search_text and '20260410' not in search_text:\n issues.append('Lot codes missing A-20260410-01')\n\n # Check for B-20260408-01\n if 'B-20260408-01' not in search_text and '20260408' not in search_text:\n issues.append('Lot codes missing B-20260408-01')\n\n if issues:\n return {'pass': False, 'score': 0.0, 'feedback': f'Row for manifest 2026-04-15-001 in {found_file.name} has issues:\\n' + '\\n'.join(issues)}\n\n return {'pass': True, 'score': 1.0, 'feedback': f'Row for manifest 2026-04-15-001 found in {found_file.name} with correct values: F={col_f}, G={col_g}, H={col_h}, I={col_i}, J={col_j}, K={col_k}, L={col_l}, M={col_m}, N={col_n}, P={col_p}, Q={col_q}, R={col_r}, S={col_s}, T={col_t}. Lot codes contain all required references including mismatch notation.'}\n", "criterion_type": "expected_output" }, { "id": "e78eb8ea-f315-42ab-aaa8-d21065c3f408", "sort_order": 1, "rubric_text": "In `mailbox.json`, a sent email to jacob.patel@prairiestar.com with cc to carlos.mendoza@prairiestar.com must exist containing text about 'LOT CODE MISMATCH', manifest '2026-04-15-001', lot codes 'A-20260412-01' and 'A-20260411-01', and 'Hold receipt open pending clarification'", "verifier_code": "from pathlib import Path\nimport json\nimport re\n\ndef verify(workspace_path, external_services_path=None):\n if not external_services_path:\n return {'pass': False, 'score': 0.0, 'feedback': 'external_services_path not provided; cannot check email'}\n \n mailbox_path = Path(external_services_path) / 'mailbox.json'\n if not mailbox_path.exists():\n return {'pass': False, 'score': 0.0, 'feedback': f'mailbox.json not found at {mailbox_path}'}\n \n with open(mailbox_path, 'r') as f:\n data = json.load(f)\n \n emails = data.get('emails', [])\n sent_emails = [e for e in emails if e.get('folder', '').lower() == 'sent']\n \n for email in sent_emails:\n to_addr = str(email.get('to_addr', '')).lower()\n cc_addr = str(email.get('cc_addr', '') or '').lower()\n body = str(email.get('body_text', '') or '').lower()\n subject = str(email.get('subject', '') or '').lower()\n combined = subject + ' ' + body\n \n if 'jacob.patel@prairiestar.com' not in to_addr:\n continue\n \n if 'carlos.mendoza@prairiestar.com' not in cc_addr:\n continue\n \n # Check for \"LOT CODE MISMATCH\" as a phrase in subject or body\n # Accept minor variations: \"lot code mismatch\", \"lot-code mismatch\", etc.\n has_lc_mismatch_phrase = bool(re.search(r'lot[\\s\\-_]*code[\\s\\-_]*mismatch', combined))\n \n has_manifest = '2026-04-15-001' in combined\n has_lot_manifest = 'a-20260412-01' in combined\n has_lot_received = 'a-20260411-01' in combined\n \n # Check for \"hold receipt open\" as a connected phrase (allow words in between)\n has_hold_open = bool(re.search(r'hold\\s+receipt\\s+open', combined))\n \n # Also accept \"hold .* open pending clarification\" as a looser but still structured match\n if not has_hold_open:\n has_hold_open = bool(re.search(r'hold\\b.*?\\bopen\\b.*?\\bpending\\b.*?\\bclarification\\b', combined))\n \n missing = []\n if not has_lc_mismatch_phrase:\n missing.append('\"LOT CODE MISMATCH\" phrase (found only scattered keyword \"mismatch\")' if 'mismatch' in combined else '\"LOT CODE MISMATCH\" phrase')\n if not has_manifest:\n missing.append('manifest 2026-04-15-001')\n if not has_lot_manifest:\n missing.append('lot A-20260412-01')\n if not has_lot_received:\n missing.append('lot A-20260411-01')\n if not has_hold_open:\n missing.append('\"Hold receipt open pending clarification\" phrase')\n \n if not missing:\n return {'pass': True, 'score': 1.0, 'feedback': f'Found sent email to jacob.patel@prairiestar.com with cc to carlos.mendoza@prairiestar.com containing LOT CODE MISMATCH template for manifest 2026-04-15-001'}\n else:\n return {'pass': False, 'score': 0.0, 'feedback': f'Found email to jacob.patel with cc carlos.mendoza but missing: {missing}'}\n \n return {'pass': False, 'score': 0.0, 'feedback': f'No sent email found to jacob.patel@prairiestar.com with cc carlos.mendoza@prairiestar.com about lot code mismatch. Checked {len(sent_emails)} sent emails.'}", "criterion_type": "expected_output" }, { "id": "f14469ac-f9fd-44fe-b08b-d15bbb125abc", "sort_order": 2, "rubric_text": "In `slack_data.json`, a message must exist in channel #receiving-houston or #waco-production-coord referencing 'P3', manifest '2026-04-15-001', and a lot code mismatch", "verifier_code": "from pathlib import Path\nimport json\n\ndef verify(workspace_path, external_services_path=None):\n if not external_services_path:\n return {'pass': False, 'score': 0.0, 'feedback': 'external_services_path not provided; cannot check Slack'}\n \n slack_path = Path(external_services_path) / 'slack_data.json'\n if not slack_path.exists():\n return {'pass': False, 'score': 0.0, 'feedback': f'slack_data.json not found at {slack_path}'}\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 # Find target channel IDs\n target_channel_names = ['receiving-houston', 'waco-production-coord']\n target_channel_ids = []\n for ch_id, ch_info in channels.items():\n ch_name = str(ch_info.get('name', '')).lower()\n for target in target_channel_names:\n if target.lower() in ch_name or ch_name in target.lower():\n target_channel_ids.append(ch_id)\n break\n \n if not target_channel_ids:\n # Try to search all channels\n target_channel_ids = list(messages.keys())\n \n for ch_id in target_channel_ids:\n ch_msgs = messages.get(ch_id, [])\n for msg in ch_msgs:\n text = str(msg.get('text', '')).lower()\n has_p3 = 'p3' in text\n has_manifest = '2026-04-15-001' in text\n has_mismatch = 'mismatch' in text or 'lot code' in text\n \n if has_p3 and has_manifest and has_mismatch:\n ch_name = channels.get(ch_id, {}).get('name', ch_id)\n return {'pass': True, 'score': 1.0, 'feedback': f'Found Slack message in channel #{ch_name} mentioning P3, manifest 2026-04-15-001, and lot code mismatch'}\n \n # Collect what was found for feedback\n found_msgs = []\n for ch_id in list(messages.keys()):\n ch_msgs = messages.get(ch_id, [])\n for msg in ch_msgs:\n text = str(msg.get('text', '')).lower()\n if '2026-04-15-001' in text or 'p3' in text:\n found_msgs.append(f'channel {ch_id}: {msg.get(\"text\", \"\")[:100]}')\n \n return {'pass': False, 'score': 0.0, 'feedback': f'No Slack message found in #receiving-houston or #waco-production-coord with P3, 2026-04-15-001, and mismatch. Target channels found: {target_channel_ids}. Related messages: {found_msgs[:3]}'}\n", "criterion_type": "expected_output" }, { "id": "b94328d5-d410-4aff-b3b8-f0aa44ec29b9", "sort_order": 3, "rubric_text": "In file `expiry_tracker.xlsx`, a row must exist for Lot Code 'A-20260410-01' with columns A-L containing: SC-001, Sweet Cream Prairie, A-20260410-01, H-A, April 15 2026 (any date format), 2026-04-10 (any date format), 18, 2027-10-10 (any date format), 542 or 543, Green, 100, Monitored. Check the actual output of the cell, NOT the formula in the cell.", "verifier_code": "from pathlib import Path\nimport openpyxl\nimport re\nfrom datetime import datetime\n\ndef verify(workspace_path, external_services_path=None):\n # Find the expiry tracker file (flexible naming)\n xlsx_files = list(Path(workspace_path).glob('**/expiry_tracker.xlsx')) + list(Path(workspace_path).glob('**/Expiry_Tracker.xlsx'))\n if not xlsx_files:\n xlsx_files = [f for f in Path(workspace_path).glob('**/*.xlsx') if 'expiry' in f.name.lower() and 'tracker' in f.name.lower()]\n if not xlsx_files:\n xlsx_files = [f for f in Path(workspace_path).glob('**/*.xlsx') if 'expiry' in f.name.lower() or 'tracker' in f.name.lower()]\n if not xlsx_files:\n return {'pass': False, 'score': 0.0, 'feedback': 'No expiry_tracker.xlsx file found in workspace'}\n\n wb = openpyxl.load_workbook(xlsx_files[0], data_only=True)\n\n # Search across all sheets for the lot code\n target_row_num = None\n lot_col = None\n target_ws = None\n\n for sheet_name in wb.sheetnames:\n ws = wb[sheet_name]\n for row in ws.iter_rows():\n for cell in row:\n if cell.value and 'a-20260410-01' in str(cell.value).lower().strip():\n target_row_num = cell.row\n lot_col = cell.column\n target_ws = ws\n break\n if target_row_num:\n break\n if target_row_num:\n break\n\n if not target_row_num or not target_ws:\n return {'pass': False, 'score': 0.0, 'feedback': 'No row found with Lot Code A-20260410-01 in expiry_tracker.xlsx'}\n\n ws = target_ws\n\n def normalize_date(val):\n if val is None:\n return None\n if isinstance(val, datetime):\n return val.strftime('%Y-%m-%d')\n s = str(val).strip()\n for fmt in ['%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', '%B %d %Y', '%b %d %Y', '%B %d, %Y', '%b %d, %Y',\n '%Y/%m/%d', '%d-%b-%Y', '%d-%B-%Y', '%d %B %Y', '%d %b %Y', '%d/%m/%Y',\n '%m-%d-%Y', '%Y%m%d', '%b %d, %y', '%B %d %Y', '%d-%m-%Y',\n '%b-%d-%Y', '%B-%d-%Y', '%m.%d.%Y', '%d.%m.%Y', '%Y.%m.%d']:\n try:\n return datetime.strptime(s, fmt).strftime('%Y-%m-%d')\n except:\n pass\n return s.lower()\n\n # Rubric says columns A-L contain 12 items:\n # A=1: SC-001\n # B=2: Sweet Cream Prairie\n # C=3: A-20260410-01\n # D=4: H-A\n # E=5: April 15 2026\n # F=6: 2026-04-10\n # G=7: 18\n # H=8: 2027-10-10\n # I=9: 542 or 543\n # J=10: Green\n # K=11: 100\n # L=12: Monitored\n #\n # The lot code (A-20260410-01) is the 3rd item, expected in column C (col index 3).\n offset = lot_col - 3\n\n def get_val(expected_col):\n return ws.cell(row=target_row_num, column=expected_col + offset).value\n\n issues = []\n\n # A=1: SC-001\n a = get_val(1)\n if a is None or 'sc-001' not in str(a).lower().replace(' ', ''):\n issues.append(f'Col A expected SC-001, got {a}')\n\n # B=2: Sweet Cream Prairie\n b = get_val(2)\n if b is None or 'sweet cream prairie' not in str(b).lower():\n issues.append(f'Col B expected Sweet Cream Prairie, got {b}')\n\n # C=3: A-20260410-01 (already confirmed by search)\n c = get_val(3)\n if c is None or 'a-20260410-01' not in str(c).lower():\n issues.append(f'Col C expected A-20260410-01, got {c}')\n\n # D=4: H-A\n d = get_val(4)\n if d is None or 'h-a' not in str(d).lower().replace(' ', ''):\n issues.append(f'Col D expected H-A, got {d}')\n\n # E=5: April 15 2026 (any date format)\n e = get_val(5)\n e_norm = normalize_date(e)\n if e_norm is None or '2026-04-15' not in e_norm:\n issues.append(f'Col E expected April 15 2026, got {e} (normalized: {e_norm})')\n\n # F=6: 2026-04-10 (any date format)\n f_val = get_val(6)\n f_norm = normalize_date(f_val)\n if f_norm is None or '2026-04-10' not in f_norm:\n issues.append(f'Col F expected 2026-04-10, got {f_val} (normalized: {f_norm})')\n\n # G=7: 18\n g = get_val(7)\n try:\n g_num = float(str(g))\n if abs(g_num - 18) > 1:\n issues.append(f'Col G expected 18, got {g}')\n except:\n issues.append(f'Col G expected 18, got {g}')\n\n # H=8: 2027-10-10 (any date format)\n h = get_val(8)\n h_norm = normalize_date(h)\n if h_norm is None or '2027-10-10' not in h_norm:\n issues.append(f'Col H expected 2027-10-10, got {h} (normalized: {h_norm})')\n\n # I=9: 542 or 543\n i_val = get_val(9)\n i_ok = False\n try:\n i_num = int(round(float(str(i_val))))\n if i_num in [542, 543]:\n i_ok = True\n except:\n pass\n if not i_ok:\n if i_val is not None and str(i_val).strip() in ['542', '543']:\n i_ok = True\n if not i_ok:\n issues.append(f'Col I expected 542 or 543, got {i_val}')\n\n # J=10: Green\n j = get_val(10)\n if j is None or 'green' not in str(j).lower():\n issues.append(f'Col J expected Green, got {j}')\n\n # K=11: 100\n k = get_val(11)\n try:\n k_num = float(str(k))\n if abs(k_num - 100) > 1:\n issues.append(f'Col K expected 100, got {k}')\n except:\n issues.append(f'Col K expected 100, got {k}')\n\n # L=12: Monitored\n l_val = get_val(12)\n if l_val is None or 'monitored' not in str(l_val).lower():\n issues.append(f'Col L expected Monitored, got {l_val}')\n\n if issues:\n return {'pass': False, 'score': 0.0, 'feedback': f'A-20260410-01 row issues in {xlsx_files[0].name}: ' + '; '.join(issues)}\n\n return {'pass': True, 'score': 1.0, 'feedback': f'A-20260410-01 row found with all correct values (A=SC-001, B=Sweet Cream Prairie, C=A-20260410-01, D=H-A, E=2026-04-15, F=2026-04-10, G=18, H=2027-10-10, I=542/543, J=Green, K=100, L=Monitored) in {xlsx_files[0].name}'}\n", "criterion_type": "expected_output" }, { "id": "999b0abb-f444-47db-863c-9623d25639be", "sort_order": 4, "rubric_text": "In file `expiry_tracker.xlsx`, a row must exist for Lot Code B-20260408-01 with columns A-L containing: SP-001, Lavender Cream Moonrise, B-20260408-01, H-B, April 15 2026 (any format), April 8 2026 (any format), 15, July 8 2027 (any format), 448 or 449, Green, 30, Monitored", "verifier_code": "from pathlib import Path\nimport openpyxl\nimport re\nfrom datetime import datetime\n\ndef verify(workspace_path, external_services_path=None):\n # Find the expiry tracker file - be lenient with naming\n xlsx_files = []\n for f in Path(workspace_path).glob('**/*.xlsx'):\n if 'expiry' in f.name.lower() or 'tracker' in f.name.lower():\n xlsx_files.append(f)\n \n if not xlsx_files:\n # Last resort: check all xlsx files\n xlsx_files = list(Path(workspace_path).glob('**/*.xlsx'))\n \n if not xlsx_files:\n return {'pass': False, 'score': 0.0, 'feedback': 'No xlsx files found in workspace'}\n \n all_feedback = []\n \n for xlsx_file in xlsx_files:\n try:\n wb = openpyxl.load_workbook(xlsx_file, data_only=True)\n except Exception as e:\n all_feedback.append(f'Could not open {xlsx_file.name}: {e}')\n continue\n \n for sheet_name in wb.sheetnames:\n ws = wb[sheet_name]\n \n # Search for the lot code B-20260408-01 anywhere in the sheet\n target_rows = []\n for row in ws.iter_rows(min_row=1, max_row=ws.max_row or 1):\n for cell in row:\n if cell.value is not None:\n val_str = str(cell.value).strip().lower().replace(' ', '')\n if 'b-20260408-01' in val_str or 'b20260408-01' in val_str or 'b-2026040801' in val_str or '20260408' in val_str:\n target_rows.append(cell.row)\n \n # Also search for SP-001\n for row in ws.iter_rows(min_row=1, max_row=ws.max_row or 1):\n for cell in row:\n if cell.value is not None:\n val_str = str(cell.value).strip().lower().replace(' ', '')\n if 'sp-001' in val_str or 'sp001' in val_str:\n if cell.row not in target_rows:\n target_rows.append(cell.row)\n \n target_rows = sorted(set(target_rows))\n \n for row_num in target_rows:\n # Collect all values in this row\n row_vals = {}\n for c in range(1, 21):\n v = ws.cell(row=row_num, column=c).value\n row_vals[c] = v\n \n def normalize_date(val):\n if val is None:\n return None\n if isinstance(val, datetime):\n return val.strftime('%Y-%m-%d')\n s = str(val).strip()\n for fmt in ['%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', '%B %d %Y', '%b %d %Y',\n '%B %d, %Y', '%b %d, %Y', '%d-%b-%Y', '%d-%B-%Y',\n '%d %B %Y', '%d %b %Y', '%Y/%m/%d', '%m-%d-%Y',\n '%d/%m/%Y', '%d/%m/%y', '%Y-%m-%dT%H:%M:%S',\n '%m/%d/%Y %H:%M', '%m/%d/%Y %H:%M:%S',\n '%B %d, %Y', '%b %d, %Y', '%d-%m-%Y',\n '%Y%m%d']:\n try:\n return datetime.strptime(s, fmt).strftime('%Y-%m-%d')\n except:\n pass\n return s.lower()\n \n def check_date(val, expected_date_str):\n if val is None:\n return False\n norm = normalize_date(val)\n if norm and expected_date_str == norm:\n return True\n raw = str(val).lower()\n parts = expected_date_str.split('-')\n year, month, day = parts[0], parts[1], parts[2]\n day_int = str(int(day))\n month_int = str(int(month))\n month_names = {1:'jan',2:'feb',3:'mar',4:'apr',5:'may',6:'jun',\n 7:'jul',8:'aug',9:'sep',10:'oct',11:'nov',12:'dec'}\n month_name = month_names.get(int(month), '')\n if year in raw and (day in raw or day_int in raw):\n if month in raw or month_int in raw or month_name in raw:\n return True\n return False\n \n def find_in_row(check_fn, start_col=1, end_col=20):\n for c in range(start_col, end_col+1):\n if check_fn(row_vals.get(c)):\n return c, row_vals.get(c)\n return None, None\n \n issues = []\n \n # Check A: SP-001\n a_ok = False\n a_val = row_vals.get(1)\n if a_val is not None and 'sp-001' in str(a_val).strip().lower().replace(' ', ''):\n a_ok = True\n if not a_ok:\n c, v = find_in_row(lambda v: v is not None and 'sp-001' in str(v).strip().lower().replace(' ', ''))\n if c:\n a_ok = True\n if not a_ok:\n issues.append(f'Expected SP-001 in row, col A has: {a_val}')\n \n # Check B: Lavender Cream Moonrise\n b_ok = False\n b_val = row_vals.get(2)\n if b_val is not None and 'lavender' in str(b_val).lower():\n b_ok = True\n if not b_ok:\n c, v = find_in_row(lambda v: v is not None and 'lavender' in str(v).lower())\n if c:\n b_ok = True\n if not b_ok:\n issues.append(f'Expected Lavender Cream Moonrise, col B has: {b_val}')\n \n # Check C: B-20260408-01\n c_ok = False\n c_val = row_vals.get(3)\n if c_val is not None and '20260408' in str(c_val).replace(' ', '').replace('-', ''):\n c_ok = True\n if not c_ok:\n col, v = find_in_row(lambda v: v is not None and '20260408' in str(v).replace(' ', '').replace('-', ''))\n if col:\n c_ok = True\n if not c_ok:\n issues.append(f'Expected B-20260408-01, col C has: {c_val}')\n \n # Check D: H-B\n d_ok = False\n d_val = row_vals.get(4)\n if d_val is not None and ('h-b' in str(d_val).lower().replace(' ', '') or str(d_val).strip().upper() == 'H-B'):\n d_ok = True\n if not d_ok:\n col, v = find_in_row(lambda v: v is not None and 'h-b' in str(v).lower().replace(' ', ''))\n if col:\n d_ok = True\n if not d_ok:\n issues.append(f'Expected H-B, col D has: {d_val}')\n \n # Check E: April 15 2026\n e_ok = False\n e_val = row_vals.get(5)\n if check_date(e_val, '2026-04-15'):\n e_ok = True\n if not e_ok:\n col, v = find_in_row(lambda v: check_date(v, '2026-04-15'))\n if col:\n e_ok = True\n if not e_ok:\n issues.append(f'Expected April 15 2026 (any format), col E has: {e_val}')\n \n # Check F: April 8 2026\n f_ok = False\n f_val = row_vals.get(6)\n if check_date(f_val, '2026-04-08'):\n f_ok = True\n if not f_ok:\n col, v = find_in_row(lambda v: check_date(v, '2026-04-08'))\n if col:\n f_ok = True\n if not f_ok:\n issues.append(f'Expected April 8 2026 (any format), col F has: {f_val}')\n \n # Check G: 15\n g_ok = False\n g_val = row_vals.get(7)\n try:\n if abs(float(str(g_val)) - 15) <= 1:\n g_ok = True\n except:\n pass\n if not g_ok:\n col, v = find_in_row(lambda v: _check_num(v, 15))\n if col:\n g_ok = True\n if not g_ok:\n issues.append(f'Expected 15, col G has: {g_val}')\n \n # Check H: July 8 2027\n h_ok = False\n h_val = row_vals.get(8)\n if check_date(h_val, '2027-07-08'):\n h_ok = True\n if not h_ok:\n col, v = find_in_row(lambda v: check_date(v, '2027-07-08'))\n if col:\n h_ok = True\n if not h_ok:\n issues.append(f'Expected July 8 2027 (any format), col H has: {h_val}')\n \n # Check I: 448 or 449\n i_ok = False\n i_val = row_vals.get(9)\n try:\n i_num = int(float(str(i_val)))\n if i_num in range(446, 452): # generous range\n i_ok = True\n except:\n pass\n if not i_ok:\n col, v = find_in_row(lambda v: _check_num_range(v, 446, 452))\n if col:\n i_ok = True\n if not i_ok:\n issues.append(f'Expected 448 or 449, col I has: {i_val}')\n \n # Check J: Green\n j_ok = False\n j_val = row_vals.get(10)\n if j_val is not None and 'green' in str(j_val).lower():\n j_ok = True\n if not j_ok:\n col, v = find_in_row(lambda v: v is not None and 'green' in str(v).lower())\n if col:\n j_ok = True\n if not j_ok:\n issues.append(f'Expected Green, col J has: {j_val}')\n \n # Check K: 30\n k_ok = False\n k_val = row_vals.get(11)\n try:\n if abs(float(str(k_val)) - 30) <= 1:\n k_ok = True\n except:\n pass\n if not k_ok:\n col, v = find_in_row(lambda v: _check_num(v, 30))\n if col:\n k_ok = True\n if not k_ok:\n issues.append(f'Expected 30, col K has: {k_val}')\n \n # Check L: Monitored\n l_ok = False\n l_val = row_vals.get(12)\n if l_val is not None and 'monitor' in str(l_val).lower():\n l_ok = True\n if not l_ok:\n col, v = find_in_row(lambda v: v is not None and 'monitor' in str(v).lower())\n if col:\n l_ok = True\n if not l_ok:\n issues.append(f'Expected Monitored, col L has: {l_val}')\n \n if not issues:\n return {'pass': True, 'score': 1.0, 'feedback': f'Row found for Lot Code B-20260408-01 with all correct values in {xlsx_file.name} (sheet: {sheet_name}, row {row_num}). Values verified: SP-001, Lavender Cream Moonrise, B-20260408-01, H-B, April 15 2026, April 8 2026, 15, July 8 2027, 448/449, Green, 30, Monitored'}\n else:\n all_feedback.append(f'{xlsx_file.name} sheet={sheet_name} row={row_num}: ' + '; '.join(issues))\n \n if all_feedback:\n return {'pass': False, 'score': 0.0, 'feedback': 'Row for Lot Code B-20260408-01 not fully correct. Details:\\n' + '\\n'.join(all_feedback)}\n return {'pass': False, 'score': 0.0, 'feedback': 'No row found with Lot Code B-20260408-01 or SP-001 in any xlsx file'}\n\ndef _check_num(v, target, tolerance=1):\n if v is None:\n return False\n try:\n return abs(float(str(v)) - target) <= tolerance\n except:\n return False\n\ndef _check_num_range(v, lo, hi):\n if v is None:\n return False\n try:\n n = int(float(str(v)))\n return lo <= n <= hi\n except:\n return False\n", "criterion_type": "expected_output" }, { "id": "8e1be04c-7887-4d8d-b33b-66937b1f65da", "sort_order": 5, "rubric_text": "In file `expiry_tracker.xlsx`, there must be exactly 9 rows including the header row, and no row must have a lot code of 'A-20260411-01'", "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('**/expiry_tracker.xlsx')) + list(Path(workspace_path).glob('**/Expiry_Tracker.xlsx'))\n if not xlsx_files:\n xlsx_files = [f for f in Path(workspace_path).glob('**/*.xlsx') if 'expiry' in f.name.lower() or 'tracker' in f.name.lower()]\n if not xlsx_files:\n return {'pass': False, 'score': 0.0, 'feedback': 'No expiry_tracker.xlsx file found in workspace'}\n \n wb = openpyxl.load_workbook(xlsx_files[0], data_only=True)\n ws = wb.active\n \n # Count non-empty rows\n row_count = 0\n for row in ws.iter_rows():\n if any(cell.value is not None for cell in row):\n row_count += 1\n \n # Check for A-20260411-01 lot code\n bad_lot_rows = []\n lot_col = None\n \n # Find lot code column\n for row in ws.iter_rows():\n for cell in row:\n if cell.value and 'lot' in str(cell.value).lower():\n lot_col = cell.column\n break\n if lot_col:\n break\n \n if lot_col:\n for row in ws.iter_rows(min_row=2):\n cell = ws.cell(row=row[0].row, column=lot_col)\n if cell.value and 'a-20260411-01' in str(cell.value).lower():\n bad_lot_rows.append(row[0].row)\n else:\n # Search all cells\n for row in ws.iter_rows(min_row=2):\n for cell in row:\n if cell.value and 'a-20260411-01' in str(cell.value).lower():\n bad_lot_rows.append(row[0].row)\n break\n \n issues = []\n if row_count != 9:\n issues.append(f'Expected exactly 9 rows (including header), found {row_count}')\n if bad_lot_rows:\n issues.append(f'Found rows with lot code A-20260411-01 (should not exist): rows {bad_lot_rows}')\n \n if issues:\n return {'pass': False, 'score': 0.0, 'feedback': f'expiry_tracker.xlsx issues: {chr(10).join(issues)}'}\n \n return {'pass': True, 'score': 1.0, 'feedback': f'expiry_tracker.xlsx has exactly 9 rows and no row with lot code A-20260411-01'}\n", "criterion_type": "incorrect_behavior" }, { "id": "84fdd603-215e-477f-9ca5-c262da309356", "sort_order": 6, "rubric_text": "In file Inbound_Receiving_Log.xlsx, a row with manifest/PO# 11587 must exist with receipt date 4/15/26, origin TexPal Logistics, Total Cases (Manifest) 50, Status 'Pre-arrival', Notes about inspecting for splinters/broken slats/stains/pest evidence and rejecting pallets unable to hold 1500 lbs; columns D, G-K, and O set to 'X' or 'N/A' (N/A may have text after as long as it is present); columns F, L-N, P-R set to 'Pending', and S set to ‘Open’.", "verifier_code": "from pathlib import Path\nimport openpyxl\nfrom datetime import datetime\n\ndef verify(workspace_path, external_services_path=None):\n # Find the file with loose matching\n xlsx_files = list(Path(workspace_path).glob('**/Inbound_Receiving_Log.xlsx')) + list(Path(workspace_path).glob('**/inbound_receiving_log.xlsx'))\n if not xlsx_files:\n xlsx_files = [f for f in Path(workspace_path).glob('**/*.xlsx') if 'inbound' in f.name.lower() or 'receiving' in f.name.lower()]\n if not xlsx_files:\n return {'pass': False, 'score': 0.0, 'feedback': 'No Inbound_Receiving_Log.xlsx found in workspace'}\n\n wb = openpyxl.load_workbook(xlsx_files[0], data_only=True)\n ws = wb.active\n\n # Find row with 11587\n target_row_num = None\n for row in ws.iter_rows():\n for cell in row:\n if cell.value is not None:\n val = str(cell.value).strip()\n if val == '11587' or val == '11587.0':\n target_row_num = cell.row\n break\n if target_row_num:\n break\n\n if not target_row_num:\n return {'pass': False, 'score': 0.0, 'feedback': 'No row found with manifest/PO# 11587 in Inbound_Receiving_Log.xlsx'}\n\n row_num = target_row_num\n\n def get_val(col_idx):\n return ws.cell(row=row_num, column=col_idx).value\n\n def normalize_date(val):\n if val is None:\n return None\n if isinstance(val, datetime):\n return val.strftime('%Y-%m-%d')\n s = str(val).strip()\n for fmt in ['%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', '%m-%d-%Y', '%m-%d-%y']:\n try:\n return datetime.strptime(s, fmt).strftime('%Y-%m-%d')\n except:\n pass\n return s\n\n def is_x_or_na(val):\n if val is None:\n return True # empty is acceptable (could be N/A)\n s = str(val).strip().lower()\n if s in ['x', 'n/a', 'na', '']:\n return True\n # N/A may have text after as long as it is present\n if s.startswith('n/a') or s.startswith('na '):\n return True\n return False\n\n def is_pending(val):\n if val is None:\n return False\n return 'pending' in str(val).strip().lower()\n\n def is_open(val):\n if val is None:\n return False\n return str(val).strip().lower() == 'open'\n\n # Gather all text from row for loose text matching\n max_col = ws.max_column or 30\n all_row_vals = []\n for c in range(1, max_col + 1):\n v = get_val(c)\n all_row_vals.append(str(v or '').lower())\n all_row_text = ' '.join(all_row_vals)\n\n issues = []\n\n # Check receipt date = 4/15/26 (i.e. April 15, 2026)\n date_found = False\n for c in range(1, max_col + 1):\n v = get_val(c)\n norm = normalize_date(v)\n if norm and norm == '2026-04-15':\n date_found = True\n break\n if not date_found:\n # Also check text representations\n if '4/15/26' in all_row_text or '4/15/2026' in all_row_text or '2026-04-15' in all_row_text or 'april 15' in all_row_text:\n date_found = True\n if not date_found:\n issues.append('Receipt date 4/15/26 not found in row')\n\n # Check origin TexPal Logistics\n if 'texpal' not in all_row_text:\n issues.append('Origin TexPal Logistics not found in row')\n\n # Check Total Cases (Manifest) = 50\n found_50 = False\n for c in range(1, max_col + 1):\n v = get_val(c)\n if v is not None:\n try:\n if abs(float(str(v)) - 50) < 1:\n found_50 = True\n break\n except:\n pass\n if not found_50:\n issues.append('Total Cases (Manifest) 50 not found in row')\n\n # Check Status = Pre-arrival\n if 'pre-arrival' not in all_row_text and 'pre arrival' not in all_row_text and 'prearrival' not in all_row_text:\n issues.append('Status Pre-arrival not found in row')\n\n # Check Notes about inspecting for splinters/broken slats/stains/pest evidence\n notes_keywords_found = 0\n for keyword in ['splinter', 'slat', 'stain', 'pest']:\n if keyword in all_row_text:\n notes_keywords_found += 1\n if notes_keywords_found < 2:\n issues.append(f'Notes about inspecting for splinters/broken slats/stains/pest evidence not sufficiently found in row (found {notes_keywords_found}/4 keywords)')\n\n # Check Notes about rejecting pallets unable to hold 1500 lbs\n if '1,500' not in all_row_text and '1500' not in all_row_text:\n issues.append('Notes about 1500 lbs not found in row')\n\n # Check columns D(4), G(7)-K(11), O(15) are X or N/A\n x_na_cols = [4, 7, 8, 9, 10, 11, 15]\n for col in x_na_cols:\n val = get_val(col)\n if not is_x_or_na(val):\n col_letter = openpyxl.utils.get_column_letter(col)\n issues.append(f'Column {col_letter} (col {col}) expected X or N/A, got \"{val}\"')\n\n # Check columns F(6), L(12)-N(14), P(16)-R(18) are Pending\n pending_cols = [6, 12, 13, 14, 16, 17, 18]\n for col in pending_cols:\n val = get_val(col)\n if not is_pending(val):\n col_letter = openpyxl.utils.get_column_letter(col)\n issues.append(f'Column {col_letter} (col {col}) expected Pending, got \"{val}\"')\n\n # Check column S(19) is 'Open'\n s_val = get_val(19)\n if not is_open(s_val):\n issues.append(f'Column S (col 19) expected Open, got \"{s_val}\"')\n\n if issues:\n return {'pass': False, 'score': 0.0, 'feedback': f'Row 11587 issues:\\n' + '\\n'.join(issues)}\n\n return {'pass': True, 'score': 1.0, 'feedback': 'Row for manifest 11587 found with all correct values: receipt date 4/15/26, TexPal Logistics, 50 cases, Pre-arrival status, correct notes about splinters/slats/stains/pest and 1500 lbs, X/N/A columns (D, G-K, O), Pending columns (F, L-N, P-R), and column S set to Open all verified.'}\n", "criterion_type": "expected_output" }, { "id": "b369268f-dbfb-437c-bca4-c28ad2901138", "sort_order": 7, "rubric_text": "In file Inbound_Receiving_Log.xlsx, a row with manifest/PO# 67204 must exist with receipt date 4/15/26, origin Lone Star Toppings Co., Total Cases (Manifest) 45, Status 'Pre-arrival', Notes about allergen alert with tree nuts and peanuts and verifying allergen labeling; columns D, G-K, and O set to 'X' or 'N/A' (N/A may have text after as long as it is present); columns F, L-N, P-R set to 'Pending', and S set to ‘Open’", "verifier_code": "from pathlib import Path\nimport openpyxl\nfrom datetime import datetime\n\ndef verify(workspace_path, external_services_path=None):\n # Find the file with loose matching\n xlsx_files = list(Path(workspace_path).glob('**/Inbound_Receiving_Log.xlsx')) + \\\n list(Path(workspace_path).glob('**/inbound_receiving_log.xlsx'))\n if not xlsx_files:\n xlsx_files = [f for f in Path(workspace_path).glob('**/*.xlsx') if 'inbound' in f.name.lower() or 'receiving' in f.name.lower()]\n if not xlsx_files:\n return {'pass': False, 'score': 0.0, 'feedback': 'No Inbound_Receiving_Log.xlsx found in workspace'}\n \n wb = openpyxl.load_workbook(xlsx_files[0], data_only=True)\n ws = wb.active\n \n # Find row containing 67204\n target_row_num = None\n for row in ws.iter_rows():\n for cell in row:\n if cell.value is not None:\n val = str(cell.value).strip()\n if val == '67204' or val == '67204.0':\n target_row_num = cell.row\n break\n if target_row_num:\n break\n \n if not target_row_num:\n return {'pass': False, 'score': 0.0, 'feedback': 'No row found with manifest/PO# 67204 in Inbound_Receiving_Log.xlsx'}\n \n row_num = target_row_num\n \n def get_val(col_idx):\n return ws.cell(row=row_num, column=col_idx).value\n \n # Collect all text in the row for broad checks\n max_col = ws.max_column or 30\n all_row_values = []\n for c in range(1, max_col + 1):\n v = get_val(c)\n all_row_values.append(v)\n all_row_text = ' '.join([str(v or '').lower() for v in all_row_values])\n \n def normalize_date(val):\n if val is None:\n return None\n if isinstance(val, datetime):\n return val.strftime('%Y-%m-%d')\n s = str(val).strip()\n for fmt in ['%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', '%m-%d-%Y', '%m-%d-%y']:\n try:\n return datetime.strptime(s, fmt).strftime('%Y-%m-%d')\n except:\n pass\n return s\n \n def is_x_or_na(val):\n \"\"\"Accept X, N/A (possibly with text after), empty/None, or NA.\"\"\"\n if val is None:\n return True\n s = str(val).strip().lower()\n if s == '':\n return True\n if s == 'x':\n return True\n if s.startswith('n/a') or s.startswith('na'):\n return True\n return False\n \n def is_pending(val):\n if val is None:\n return False\n return 'pending' in str(val).strip().lower()\n \n def is_open(val):\n if val is None:\n return False\n return str(val).strip().lower() == 'open'\n \n issues = []\n \n # Check receipt date = 4/15/26 (i.e., 2026-04-15)\n date_found = False\n date_checks = ['2026-04-15', '4/15/26', '4/15/2026', 'april 15']\n for dc in date_checks:\n if dc in all_row_text:\n date_found = True\n break\n if not date_found:\n for c in range(1, max_col + 1):\n norm = normalize_date(get_val(c))\n if norm and '2026-04-15' in norm:\n date_found = True\n break\n if not date_found:\n issues.append('Receipt date 4/15/26 not found in row')\n \n # Check origin Lone Star Toppings\n if 'lone star' not in all_row_text:\n issues.append('Origin Lone Star Toppings Co. not found in row')\n \n # Check Total Cases = 45\n found_45 = False\n for c in range(1, max_col + 1):\n v = get_val(c)\n if v is not None:\n try:\n if abs(float(str(v)) - 45) < 1:\n found_45 = True\n break\n except:\n pass\n if not found_45:\n issues.append('Total Cases (Manifest) 45 not found in row')\n \n # Check Status = Pre-arrival\n if 'pre-arrival' not in all_row_text and 'pre arrival' not in all_row_text and 'prearrival' not in all_row_text:\n issues.append('Status Pre-arrival not found in row')\n \n # Check Notes content - allergen\n if 'allergen' not in all_row_text:\n issues.append('Notes about allergen alert not found in row')\n if 'tree nut' not in all_row_text and 'treenut' not in all_row_text and 'peanut' not in all_row_text:\n issues.append('Notes about tree nuts/peanuts not found in row')\n \n # Check columns D(4), G(7)-K(11), O(15) are X or N/A\n x_na_cols = [4, 7, 8, 9, 10, 11, 15]\n for col in x_na_cols:\n val = get_val(col)\n if not is_x_or_na(val):\n issues.append(f'Column {col} (letter {chr(64+col)}) expected X or N/A, got \"{val}\"')\n \n # Check columns F(6), L(12)-N(14), P(16)-R(18) are Pending\n pending_cols = [6, 12, 13, 14, 16, 17, 18]\n for col in pending_cols:\n val = get_val(col)\n if not is_pending(val):\n issues.append(f'Column {col} (letter {chr(64+col)}) expected Pending, got \"{val}\"')\n \n # Check column S(19) is Open\n s_val = get_val(19)\n if not is_open(s_val):\n issues.append(f'Column 19 (letter S) expected Open, got \"{s_val}\"')\n \n if issues:\n return {'pass': False, 'score': 0.0, 'feedback': f'Row 67204 issues:\\n' + '\\n'.join(issues)}\n \n return {'pass': True, 'score': 1.0, 'feedback': 'Row for manifest 67204 found with all correct values (receipt date 4/15/26, Lone Star Toppings Co., 45 cases, Pre-arrival status, allergen notes about tree nuts/peanuts, columns D/G-K/O set to X or N/A, columns F/L-N/P-R set to Pending, column S set to Open)'}\n", "criterion_type": "expected_output" }, { "id": "f2e1929e-2228-4d11-9fd6-8d79cbb6d35a", "sort_order": 8, "rubric_text": "In file `temperature_log.xlsx`, there must be exactly 23 rows including the header row", "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('**/temperature_log.xlsx')) + list(Path(workspace_path).glob('**/Temperature_Log.xlsx'))\n if not xlsx_files:\n xlsx_files = [f for f in Path(workspace_path).glob('**/*.xlsx') if 'temperature' in f.name.lower() or 'temp_log' in f.name.lower()]\n if not xlsx_files:\n return {'pass': False, 'score': 0.0, 'feedback': 'No temperature_log.xlsx file found in workspace'}\n \n wb = openpyxl.load_workbook(xlsx_files[0], data_only=True)\n ws = wb.active\n \n row_count = 0\n for row in ws.iter_rows():\n if any(cell.value is not None for cell in row):\n row_count += 1\n \n if row_count != 23:\n return {'pass': False, 'score': 0.0, 'feedback': f'temperature_log.xlsx has {row_count} non-empty rows, expected exactly 23 (including header)'}\n \n return {'pass': True, 'score': 1.0, 'feedback': f'temperature_log.xlsx has exactly 23 rows including header'}\n", "criterion_type": "incorrect_behavior" }, { "id": "c3753422-0cdb-427c-9bbf-4dcd10e2c1c6", "sort_order": 9, "rubric_text": "In file `inventory_master.xlsx`, there must be exactly 7 rows including the header row", "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('**/inventory_master.xlsx')) + list(Path(workspace_path).glob('**/Inventory_Master.xlsx'))\n if not xlsx_files:\n xlsx_files = [f for f in Path(workspace_path).glob('**/*.xlsx') if 'inventory' in f.name.lower() and 'master' in f.name.lower()]\n if not xlsx_files:\n return {'pass': False, 'score': 0.0, 'feedback': 'No inventory_master.xlsx file found in workspace'}\n \n wb = openpyxl.load_workbook(xlsx_files[0], data_only=True)\n ws = wb.active\n \n row_count = 0\n for row in ws.iter_rows():\n if any(cell.value is not None for cell in row):\n row_count += 1\n \n if row_count != 7:\n return {'pass': False, 'score': 0.0, 'feedback': f'inventory_master.xlsx has {row_count} non-empty rows, expected exactly 7 (including header)'}\n \n return {'pass': True, 'score': 1.0, 'feedback': f'inventory_master.xlsx has exactly 7 rows including header'}\n", "criterion_type": "incorrect_behavior" }, { "id": "rubric_1776513856839", "sort_order": 10, "rubric_text": "There should be no Slack DM sent to Alicia Nguyen.", "verifier_code": "from pathlib import Path\nimport json\n\ndef verify(workspace_path, external_services_path=None):\n # We need to check external services (Slack) to verify no DM was sent to Alicia Nguyen.\n # Slack messages might be stored in external_services_path.\n \n if external_services_path is None:\n # If no external services path is provided, we can't confirm Slack messages.\n # But since all 3 examples failed, we should check workspace for any Slack-related logs too.\n # Be generous: if we can't check, we pass (prefer false positives).\n return {\"pass\": True, \"score\": 1.0, \"feedback\": \"No external_services_path provided to check Slack messages. Cannot confirm DMs were sent, so passing by default.\"}\n \n ext_path = Path(external_services_path)\n \n # Check for Slack data in various possible file locations\n slack_files = [\n ext_path / \"slack_data.json\",\n ext_path / \"slack_messages.json\",\n ext_path / \"slack.json\",\n ]\n \n found_slack_file = None\n slack_data = None\n \n for sf in slack_files:\n if sf.exists():\n found_slack_file = sf\n try:\n with open(sf, 'r') as f:\n slack_data = json.load(f)\n except Exception as e:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": f\"Error reading Slack data file {sf}: {e}\"}\n break\n \n if found_slack_file is None:\n # Also try to find any json file that might contain slack data\n for jf in ext_path.glob(\"*.json\"):\n try:\n with open(jf, 'r') as f:\n data = json.load(f)\n # Check if this looks like slack data\n if isinstance(data, dict) and any(k in data for k in ['messages', 'channels', 'dms', 'direct_messages', 'ims']):\n slack_data = data\n found_slack_file = jf\n break\n except:\n continue\n \n if slack_data is None:\n return {\"pass\": True, \"score\": 1.0, \"feedback\": \"No Slack data file found in external services. Cannot confirm any DMs were sent, passing by default.\"}\n \n # Now search for DMs to Alicia Nguyen\n alicia_variants = [\"alicia nguyen\", \"alicia_nguyen\", \"alicia.nguyen\", \"nguyen, alicia\", \"alicianguyen\"]\n \n def is_alicia(text):\n if text is None:\n return False\n text_lower = text.lower().strip()\n for variant in alicia_variants:\n if variant in text_lower:\n return True\n return False\n \n dm_found = False\n dm_details = []\n \n # Check various possible structures for Slack DMs\n def search_messages(obj, path=\"\"):\n nonlocal dm_found, dm_details\n if isinstance(obj, dict):\n # Check if this dict represents a message/DM to Alicia\n to_field = obj.get('to') or obj.get('recipient') or obj.get('to_user') or obj.get('recipient_name') or obj.get('channel_name') or obj.get('dm_to') or ''\n user_field = obj.get('user') or obj.get('username') or obj.get('user_name') or ''\n channel_field = obj.get('channel') or obj.get('channel_name') or ''\n \n # Check if it's a DM context directed at Alicia\n if is_alicia(str(to_field)) or (is_alicia(str(channel_field)) and ('dm' in path.lower() or 'direct' in path.lower() or 'im' in path.lower())):\n dm_found = True\n dm_details.append(f\"Found DM to Alicia Nguyen at path={path}: {json.dumps(obj)[:300]}\")\n \n for k, v in obj.items():\n search_messages(v, f\"{path}.{k}\")\n elif isinstance(obj, list):\n for i, item in enumerate(obj):\n search_messages(item, f\"{path}[{i}]\")\n \n search_messages(slack_data)\n \n if dm_found:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": f\"FAIL: Found Slack DM(s) sent to Alicia Nguyen. Details: {'; '.join(dm_details)}\"}\n else:\n return {\"pass\": True, \"score\": 1.0, \"feedback\": f\"PASS: No Slack DMs to Alicia Nguyen found in Slack data from {found_slack_file}.\"}\n", "criterion_type": "incorrect_behavior" } ]