Files
2026-06-29 10:08:59 -07:00

80 lines
57 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
[
{
"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"
}
]