[ { "id": "7e23756f-b4ae-4663-a74d-790bd570af74", "sort_order": 0, "rubric_text": "In `calendar_data.json` (external services), there must be exactly 286 events in the events object.", "verifier_code": "from pathlib import Path\nimport json\n\ndef verify(workspace_path, external_services_path=None):\n if external_services_path is None:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"external_services_path is None; cannot check calendar_data.json\"}\n cal_path = Path(external_services_path) / \"calendar_data.json\"\n if not cal_path.exists():\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"calendar_data.json not found at external_services_path\"}\n with open(cal_path, \"r\") as f:\n data = json.load(f)\n events = data.get(\"events\", {})\n count = len(events)\n if count == 286:\n return {\"pass\": True, \"score\": 1.0, \"feedback\": f\"calendar_data.json contains exactly 286 events as required.\"}\n else:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": f\"Expected exactly 286 events in calendar_data.json, but found {count}.\"}\n", "criterion_type": "incorrect_behavior" }, { "id": "03437a49-686c-493e-8f2a-4af41397970e", "sort_order": 1, "rubric_text": "In `calendar_data.json` (external services), there must be an event with summary 'Exit Interview – James Smith' (or close variant) starting at 3:30 PM and ending at 4:30 PM on February 12th, 2026.", "verifier_code": "from pathlib import Path\nimport json\nfrom datetime import datetime\nimport re\n\ndef verify(workspace_path, external_services_path=None):\n if external_services_path is None:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"external_services_path is None; cannot check calendar_data.json\"}\n cal_path = Path(external_services_path) / \"calendar_data.json\"\n if not cal_path.exists():\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"calendar_data.json not found\"}\n with open(cal_path, \"r\") as f:\n data = json.load(f)\n\n events = data.get(\"events\", {})\n if isinstance(events, dict):\n iterator = list(events.items())\n elif isinstance(events, list):\n iterator = [(ev.get(\"id\", f\"idx-{i}\"), ev) for i, ev in enumerate(events)]\n else:\n iterator = []\n\n def _dt(v):\n if isinstance(v, dict):\n return v.get(\"dateTime\") or v.get(\"date\") or \"\"\n return v or \"\"\n\n target_summary_pattern = re.compile(r'exit\\s+interview.*james\\s+smith', re.IGNORECASE)\n matches = [(eid, ev) for eid, ev in iterator if target_summary_pattern.search(ev.get(\"summary\", \"\"))]\n if not matches:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"No event matching 'Exit Interview - James Smith' found in calendar_data.json\"}\n\n last_feedback = \"No matching event had the expected time.\"\n for eid, ev in matches:\n start_str = _dt(ev.get(\"start\", \"\"))\n end_str = _dt(ev.get(\"end\", \"\"))\n parsed = False\n for fmt in [\"%Y-%m-%dT%H:%M:%S\", \"%Y-%m-%dT%H:%M\", \"%Y-%m-%d %H:%M:%S\", \"%Y-%m-%d %H:%M\"]:\n try:\n start_dt = datetime.strptime(start_str[:19], fmt)\n end_dt = datetime.strptime(end_str[:19], fmt)\n parsed = True\n if (start_dt.year == 2026 and start_dt.month == 2 and start_dt.day == 12\n and start_dt.hour == 15 and start_dt.minute == 30\n and end_dt.year == 2026 and end_dt.month == 2 and end_dt.day == 12\n and end_dt.hour == 16 and end_dt.minute == 30):\n return {\"pass\": True, \"score\": 1.0, \"feedback\": f\"Found 'Exit Interview - James Smith' event on 2026-02-12 15:30-16:30. Event ID: {eid}\"}\n last_feedback = f\"Found event matching 'Exit Interview - James Smith' but wrong time: start={start_str}, end={end_str}. Expected 2026-02-12 15:30-16:30.\"\n break\n except ValueError:\n continue\n if not parsed:\n last_feedback = f\"Found matching event but could not parse start/end times: start={start_str}, end={end_str}\"\n\n return {\"pass\": False, \"score\": 0.0, \"feedback\": last_feedback}", "criterion_type": "expected_output" }, { "id": "96456488-26d3-46ed-adda-a47ce5e4da2c", "sort_order": 2, "rubric_text": "In `calendar_data.json` (external services), there must be an event with summary 'Exit Interview – Teresa Romero' (or close variant) starting at 9:00 AM and ending at 9:30 AM on February 13th, 2026.", "verifier_code": "from pathlib import Path\nimport json\nfrom datetime import datetime\nimport re\n\ndef verify(workspace_path, external_services_path=None):\n if external_services_path is None:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"external_services_path is None; cannot check calendar_data.json\"}\n cal_path = Path(external_services_path) / \"calendar_data.json\"\n if not cal_path.exists():\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"calendar_data.json not found\"}\n with open(cal_path, \"r\") as f:\n data = json.load(f)\n\n events = data.get(\"events\", {})\n if isinstance(events, dict):\n iterator = list(events.items())\n elif isinstance(events, list):\n iterator = [(ev.get(\"id\", f\"idx-{i}\"), ev) for i, ev in enumerate(events)]\n else:\n iterator = []\n\n def _dt(v):\n if isinstance(v, dict):\n return v.get(\"dateTime\") or v.get(\"date\") or \"\"\n return v or \"\"\n\n target_summary_pattern = re.compile(r'exit\\s+interview.*teresa\\s+romero', re.IGNORECASE)\n matches = [(eid, ev) for eid, ev in iterator if target_summary_pattern.search(ev.get(\"summary\", \"\"))]\n if not matches:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"No event matching 'Exit Interview - Teresa Romero' found in calendar_data.json\"}\n\n last_feedback = \"No matching event had the expected time.\"\n for eid, ev in matches:\n start_str = _dt(ev.get(\"start\", \"\"))\n end_str = _dt(ev.get(\"end\", \"\"))\n parsed = False\n for fmt in [\"%Y-%m-%dT%H:%M:%S\", \"%Y-%m-%dT%H:%M\", \"%Y-%m-%d %H:%M:%S\", \"%Y-%m-%d %H:%M\"]:\n try:\n start_dt = datetime.strptime(start_str[:19], fmt)\n end_dt = datetime.strptime(end_str[:19], fmt)\n parsed = True\n if (start_dt.year == 2026 and start_dt.month == 2 and start_dt.day == 13\n and start_dt.hour == 9 and start_dt.minute == 0\n and end_dt.year == 2026 and end_dt.month == 2 and end_dt.day == 13\n and end_dt.hour == 9 and end_dt.minute == 30):\n return {\"pass\": True, \"score\": 1.0, \"feedback\": f\"Found 'Exit Interview - Teresa Romero' event on 2026-02-13 09:00-09:30. Event ID: {eid}\"}\n last_feedback = f\"Found event matching 'Exit Interview - Teresa Romero' but wrong time: start={start_str}, end={end_str}. Expected 2026-02-13 09:00-09:30.\"\n break\n except ValueError:\n continue\n if not parsed:\n last_feedback = f\"Found matching event but could not parse times: start={start_str}, end={end_str}\"\n\n return {\"pass\": False, \"score\": 0.0, \"feedback\": last_feedback}", "criterion_type": "expected_output" }, { "id": "b5f413ed-89f3-4cb6-af6a-32234779af2e", "sort_order": 3, "rubric_text": "In `calendar_data.json` (external services), there must be an event with summary 'Exit Interview – Gabriel Tran' (or close variant) starting at 2:00 PM and ending at 2:30 PM on February 20th, 2026.", "verifier_code": "from pathlib import Path\nimport json\nfrom datetime import datetime\nimport re\n\ndef verify(workspace_path, external_services_path=None):\n if external_services_path is None:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"external_services_path is None; cannot check calendar_data.json\"}\n cal_path = Path(external_services_path) / \"calendar_data.json\"\n if not cal_path.exists():\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"calendar_data.json not found\"}\n with open(cal_path, \"r\") as f:\n data = json.load(f)\n\n events = data.get(\"events\", {})\n if isinstance(events, dict):\n iterator = list(events.items())\n elif isinstance(events, list):\n iterator = [(ev.get(\"id\", f\"idx-{i}\"), ev) for i, ev in enumerate(events)]\n else:\n iterator = []\n\n def _dt(v):\n if isinstance(v, dict):\n return v.get(\"dateTime\") or v.get(\"date\") or \"\"\n return v or \"\"\n\n target_summary_pattern = re.compile(r'exit\\s+interview.*gabriel\\s+tran', re.IGNORECASE)\n matches = [(eid, ev) for eid, ev in iterator if target_summary_pattern.search(ev.get(\"summary\", \"\"))]\n if not matches:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"No event matching 'Exit Interview - Gabriel Tran' found in calendar_data.json\"}\n\n last_feedback = \"No matching event had the expected time.\"\n for eid, ev in matches:\n start_str = _dt(ev.get(\"start\", \"\"))\n end_str = _dt(ev.get(\"end\", \"\"))\n parsed = False\n for fmt in [\"%Y-%m-%dT%H:%M:%S\", \"%Y-%m-%dT%H:%M\", \"%Y-%m-%d %H:%M:%S\", \"%Y-%m-%d %H:%M\"]:\n try:\n start_dt = datetime.strptime(start_str[:19], fmt)\n end_dt = datetime.strptime(end_str[:19], fmt)\n parsed = True\n if (start_dt.year == 2026 and start_dt.month == 2 and start_dt.day == 20\n and start_dt.hour == 14 and start_dt.minute == 0\n and end_dt.year == 2026 and end_dt.month == 2 and end_dt.day == 20\n and end_dt.hour == 14 and end_dt.minute == 30):\n return {\"pass\": True, \"score\": 1.0, \"feedback\": f\"Found 'Exit Interview - Gabriel Tran' event on 2026-02-20 14:00-14:30. Event ID: {eid}\"}\n last_feedback = f\"Found event matching 'Exit Interview - Gabriel Tran' but wrong time: start={start_str}, end={end_str}. Expected 2026-02-20 14:00-14:30.\"\n break\n except ValueError:\n continue\n if not parsed:\n last_feedback = f\"Found matching event but could not parse times: start={start_str}, end={end_str}\"\n\n return {\"pass\": False, \"score\": 0.0, \"feedback\": last_feedback}", "criterion_type": "expected_output" }, { "id": "8501d551-7380-4a22-b33a-59b96f322492", "sort_order": 4, "rubric_text": "In `employee_roster.xlsx` (workspace), rows with IDs E-1052, E-1064, and E-1158 in column A must have the correct values across columns A through O as specified.", "verifier_code": "from pathlib import Path\nimport re\n\ndef verify(workspace_path, external_services_path=None):\n try:\n import openpyxl\n except ImportError:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"openpyxl not available\"}\n\n xlsx_files = list(Path(workspace_path).glob(\"*.xlsx\"))\n roster_files = [f for f in xlsx_files if \"roster\" in f.name.lower() or \"employee\" in f.name.lower()]\n if not roster_files:\n roster_files = xlsx_files\n if not roster_files:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"No .xlsx file found in workspace\"}\n\n # Expected rows: key=ID, value=list of expected values for cols A-O (0-indexed 0-14)\n # Blanks are represented as None\n expected_rows = {\n \"E-1052\": [\"E-1052\", \"Teresa\", \"Romero\", \"t.romero@crestwood.edu\", \"Library Services\", \"Main\", \"B. Mendoza\", \"10/24/2013\", \"Non-Exempt\", \"Full-Time\", 1369, \"Active\", None, None, \"Remote work agreement on file — WFH Tuesdays and Thursdays.\"],\n \"E-1064\": [\"E-1064\", \"James\", \"Smith\", \"j.smith@crestwood.edu\", \"Student Affairs\", \"Main\", \"B. Fernandez\", \"04/29/2025\", \"Non-Exempt\", \"Full-Time\", 1908, \"Active\", None, None, None],\n \"E-1158\": [\"E-1158\", \"Gabriel\", \"Tran\", \"g.tran@crestwood.edu\", \"Student Affairs\", \"Main\", \"E. Baker\", \"01/13/2008\", \"Non-Exempt\", \"Full-Time\", 1961, \"Active\", None, None, \"Flex schedule approved Mon/Wed WFH.\"],\n }\n\n def normalize(val):\n if val is None:\n return \"\"\n return str(val).strip()\n\n def date_match(actual, expected_str):\n # Accept various date formats - just check month/day/year numbers\n import re\n nums_actual = re.findall(r'\\d+', str(actual))\n nums_expected = re.findall(r'\\d+', expected_str)\n if len(nums_actual) >= 3 and len(nums_expected) >= 3:\n # expected is MM/DD/YYYY\n exp_month, exp_day, exp_year = nums_expected[0], nums_expected[1], nums_expected[2]\n act_flat = ''.join(nums_actual)\n return exp_month in act_flat and exp_day in act_flat and exp_year in act_flat\n return normalize(actual) == expected_str\n\n results = {}\n for xlsx_file in roster_files:\n try:\n wb = openpyxl.load_workbook(xlsx_file, data_only=True)\n except Exception as e:\n continue\n for ws in wb.worksheets:\n for row in ws.iter_rows():\n if not row:\n continue\n cell_a = normalize(row[0].value)\n if cell_a in expected_rows:\n exp = expected_rows[cell_a]\n row_vals = [cell.value for cell in row[:15]]\n mismatches = []\n for i, (actual_val, exp_val) in enumerate(zip(row_vals, exp)):\n col_letter = chr(ord('A') + i)\n if exp_val is None:\n # Blank expected\n if actual_val is not None and str(actual_val).strip() != \"\":\n mismatches.append(f\"Col {col_letter}: expected blank, got '{actual_val}'\")\n elif i == 7: # Date column\n if not date_match(actual_val, exp_val):\n mismatches.append(f\"Col {col_letter}: expected '{exp_val}', got '{actual_val}'\")\n elif i == 10: # Numeric (ext)\n try:\n if abs(float(str(actual_val).strip()) - float(str(exp_val))) > 1:\n mismatches.append(f\"Col {col_letter}: expected '{exp_val}', got '{actual_val}'\")\n except:\n if normalize(actual_val) != str(exp_val):\n mismatches.append(f\"Col {col_letter}: expected '{exp_val}', got '{actual_val}'\")\n elif i == 14: # Notes - check key content loosely\n if exp_val and normalize(actual_val).lower() != normalize(exp_val).lower():\n # Allow partial/fuzzy match for notes\n if not (normalize(exp_val).lower()[:20] in normalize(actual_val).lower()):\n mismatches.append(f\"Col {col_letter}: expected '{exp_val}', got '{actual_val}'\")\n else:\n if normalize(actual_val).lower() != normalize(exp_val).lower():\n mismatches.append(f\"Col {col_letter}: expected '{exp_val}', got '{actual_val}'\")\n results[cell_a] = mismatches\n\n missing = [eid for eid in expected_rows if eid not in results]\n if missing:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": f\"Could not find rows for IDs: {missing} in any .xlsx file\"}\n\n all_mismatches = {}\n for eid, mm in results.items():\n if mm:\n all_mismatches[eid] = mm\n\n if not all_mismatches:\n return {\"pass\": True, \"score\": 1.0, \"feedback\": \"All three rows (E-1052, E-1064, E-1158) have correct values in columns A-O.\"}\n else:\n details = '; '.join([f\"{eid}: {mms}\" for eid, mms in all_mismatches.items()])\n return {\"pass\": False, \"score\": 0.0, \"feedback\": f\"Mismatches found: {details}\"}\n", "criterion_type": "incorrect_behavior" }, { "id": "787cf3b0-251c-4627-a730-3d68eb3a234b", "sort_order": 5, "rubric_text": "In `jira_state.json` (external services), the issues 'Offboarding — Smith, James (E-1064)', 'Offboarding — Tran, Gabriel (E-1158)', and 'Offboarding — Romero, Teresa (E-1052)' must each have exactly 2 comments (the initial fixture count; no new comments added).", "verifier_code": "from pathlib import Path\nimport json\nimport re\n\ndef verify(workspace_path, external_services_path=None):\n if external_services_path is None:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"external_services_path is None; cannot check jira_state.json\"}\n jira_path = Path(external_services_path) / \"jira_state.json\"\n if not jira_path.exists():\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"jira_state.json not found\"}\n with open(jira_path, \"r\") as f:\n data = json.load(f)\n\n if isinstance(data, list):\n issues = data\n elif isinstance(data, dict):\n raw = data.get(\"issues\", data)\n if isinstance(raw, dict):\n issues = list(raw.values())\n elif isinstance(raw, list):\n issues = raw\n else:\n issues = []\n else:\n issues = []\n\n def _summary(issue):\n if not isinstance(issue, dict):\n return \"\"\n fields = issue.get(\"fields\", {}) if isinstance(issue.get(\"fields\"), dict) else {}\n return fields.get(\"summary\") or issue.get(\"summary\") or issue.get(\"title\") or issue.get(\"name\") or \"\"\n\n def _comment_count(issue):\n if not isinstance(issue, dict):\n return 0\n fields = issue.get(\"fields\", {}) if isinstance(issue.get(\"fields\"), dict) else {}\n comment = fields.get(\"comment\")\n if isinstance(comment, dict):\n inner = comment.get(\"comments\", [])\n if isinstance(inner, list):\n return len(inner)\n if isinstance(comment, list):\n return len(comment)\n top = issue.get(\"comments\")\n if isinstance(top, list):\n return len(top)\n if isinstance(top, dict):\n inner = top.get(\"comments\", top)\n if isinstance(inner, list):\n return len(inner)\n return 0\n\n # Three issues as specified in the rubric\n targets = [\n (\"Offboarding \\u2014 Smith, James (E-1064)\", re.compile(r'smith.*james.*e-?1064', re.IGNORECASE), 2),\n (\"Offboarding \\u2014 Tran, Gabriel (E-1158)\", re.compile(r'tran.*gabriel.*e-?1158', re.IGNORECASE), 2),\n (\"Offboarding \\u2014 Romero, Teresa (E-1052)\", re.compile(r'romero.*teresa.*e-?1052', re.IGNORECASE), 2),\n ]\n\n found = {label: None for label, _, _ in targets}\n for issue in issues:\n summary = _summary(issue)\n if not summary:\n continue\n for label, pat, _ in targets:\n if found[label] is None and pat.search(summary):\n found[label] = issue\n\n missing = [label for label, iss in found.items() if iss is None]\n if missing:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": f\"Could not find Jira issues: {missing}\"}\n\n failures = []\n for label, _, expected in targets:\n actual = _comment_count(found[label])\n if actual != expected:\n failures.append(f\"Issue '{label}' has {actual} comments (expected {expected})\")\n\n if failures:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"; \".join(failures)}\n return {\"pass\": True, \"score\": 1.0, \"feedback\": \"All three issues ('Offboarding \\u2014 Smith, James (E-1064)', 'Offboarding \\u2014 Tran, Gabriel (E-1158)', and 'Offboarding \\u2014 Romero, Teresa (E-1052)') each have exactly 2 comments \\u2014 no new comments were added.\"}", "criterion_type": "incorrect_behavior" }, { "id": "d034660f-c02f-4fc9-b048-904ebc881d05", "sort_order": 6, "rubric_text": "In `mailbox.json` (external services), there must be exactly 7 emails in the emails array.", "verifier_code": "from pathlib import Path\nimport json\n\ndef verify(workspace_path, external_services_path=None):\n if external_services_path is None:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"external_services_path is None; cannot check mailbox.json\"}\n mailbox_path = Path(external_services_path) / \"mailbox.json\"\n if not mailbox_path.exists():\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"mailbox.json not found\"}\n with open(mailbox_path, \"r\") as f:\n data = json.load(f)\n emails = data.get(\"emails\", [])\n count = len(emails)\n if count == 7:\n return {\"pass\": True, \"score\": 1.0, \"feedback\": f\"mailbox.json contains exactly 7 emails as required.\"}\n else:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": f\"Expected exactly 7 emails in mailbox.json, but found {count}.\"}\n", "criterion_type": "incorrect_behavior" }, { "id": "576a38a2-aee1-4c3a-8ae7-ecdd26493cbc", "sort_order": 7, "rubric_text": "In `jira_state.json` (external services), there must be exactly 17 issues.", "verifier_code": "from pathlib import Path\nimport json\n\ndef verify(workspace_path, external_services_path=None):\n if external_services_path is None:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"external_services_path is None; cannot check jira_state.json\"}\n jira_path = Path(external_services_path) / \"jira_state.json\"\n if not jira_path.exists():\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"jira_state.json not found\"}\n with open(jira_path, \"r\") as f:\n data = json.load(f)\n\n if isinstance(data, list):\n issues = data\n elif isinstance(data, dict):\n if \"issues\" in data:\n issues = data[\"issues\"]\n else:\n issues = list(data.values())\n else:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": \"Unexpected jira_state.json format\"}\n\n count = len(issues)\n if count == 17:\n return {\"pass\": True, \"score\": 1.0, \"feedback\": f\"jira_state.json contains exactly 17 issues as required.\"}\n else:\n return {\"pass\": False, \"score\": 0.0, \"feedback\": f\"Expected exactly 17 issues in jira_state.json, but found {count}.\"}\n", "criterion_type": "incorrect_behavior" } ]