Task: workarena.servicenow.create-change-request
Goal: Create a new change request with a value of "unfuddled Mar cionotomy palaeoethnology extend" for field "Test plan", a value of "A failed RAID controller card needs to be replaced on PSORA1" for field "Short description", a value of "Unsuccessful" for field "Close code", a value of "Network" for field "Category", a value of "Moderate" for field "Risk", and a value of "Fail PSORA1 to DR systemShutdown SystemRemove failed RAID cardInstall new RAID cardBoot systemConfigure RAID cardBring system onlineValidate access to disk structuresFailback from DR to PSORA1" for field "Implementation plan".
Task configuration: {'table_name': 'change_request', 'task_fields': ['test_plan', 'short_description', 'close_code', 'category', 'risk', 'implementation_plan'], 'template_record': {'active': 'true', 'activity_due': 'UNKNOWN', 'additional_assignee_list': '', 'approval': 'Requested', 'approval_history': '2023-10-08 06:09:56 - System Administrator (Approval history)\nGroup approval for Database approved by user Fred Luddy (Technical approvals).\n\n', 'approval_set': '', 'assigned_to': {'display_value': 'David Loo', 'link': 'https://dev215901.service-now.com/api/now/table/sys_user/5137153cc611227c000bbd1bd8cd2007'}, 'assignment_group': 'Database', 'backout_plan': 'philately talipat chloropalladic unlevelly Mesozoa', 'business_duration': '', 'business_service': '', 'cab_date_time': '', 'cab_delegate': '', 'cab_recommendation': '', 'cab_required': 'false', 'calendar_duration': '', 'category': 'Network', 'change_plan': '', 'chg_model': '', 'close_code': 'Unsuccessful', 'close_notes': 'gateage oversteadfast Platycephalidae Siculi intercensal', 'closed_at': '', 'closed_by': '', 'cmdb_ci': '', 'comments': '', 'comments_and_work_notes': '', 'company': '', 'conflict_last_run': '', 'conflict_status': 'Not Run', 'contact_type': None, 'contract': '', 'correlation_display': '', 'correlation_id': '', 'delivery_plan': '', 'delivery_task': '', 'description': '01:00.0 RAID bus controller: Adaptec AAC-RAID has failed on PSORA1 and needs to be replaced immediately.', 'due_date': '', 'end_date': '2023-11-21 06:30:00', 'escalation': 'Normal', 'expected_start': '', 'follow_up': '', 'group_list': '', 'impact': '2 - Medium', 'implementation_plan': 'Fail PSORA1 to DR systemShutdown SystemRemove failed RAID cardInstall new RAID cardBoot systemConfigure RAID cardBring system onlineValidate access to disk structuresFailback from DR to PSORA1', 'justification': 'metallorganic sutorian cervisia nonfloating laboriousness', 'knowledge': 'false', 'location': '', 'made_sla': 'true', 'number': 'CHG0000057', 'on_hold': 'false', 'on_hold_reason': '', 'on_hold_task': '', 'opened_at': '2023-10-06 01:21:33', 'opened_by': {'display_value': 'System Administrator', 'link': 'https://dev215901.service-now.com/api/now/table/sys_user/6816f79cc0a8016401c5a33be04be441'}, 'order': '', 'outside_maintenance_schedule': 'false', 'parent': '', 'phase': None, 'phase_state': 'Open', 'priority': '2 - High', 'production_system': 'false', 'reason': None, 'reassignment_count': '0', 'requested_by': {'display_value': 'System Administrator', 'link': 'https://dev215901.service-now.com/api/now/table/sys_user/6816f79cc0a8016401c5a33be04be441'}, 'requested_by_date': '', 'review_comments': '', 'review_date': '', 'review_status': '', 'risk': 'Moderate', 'risk_impact_analysis': 'stiffness rah homily compose intercept', 'route_reason': '', 'scope': 'Medium', 'service_offering': '', 'short_description': 'A failed RAID controller card needs to be replaced on PSORA1', 'sla_due': 'UNKNOWN', 'start_date': '2023-11-21 02:30:00', 'state': 'Authorize', 'std_change_producer_version': '', 'sys_class_name': 'Change Request', 'sys_created_by': 'admin', 'sys_created_on': '2023-10-06 01:21:33', 'sys_domain': {'display_value': 'global', 'link': 'https://dev215901.service-now.com/api/now/table/sys_user_group/global'}, 'sys_domain_path': '/', 'sys_id': '6dcdf152db252200a6a2b31be0b8f5fc', 'sys_mod_count': '11', 'sys_tags': '', 'sys_updated_by': 'admin', 'sys_updated_on': '2023-10-09 01:45:26', 'task_effective_number': 'CHG0000057', 'test_plan': 'unfuddled Mar cionotomy palaeoethnology extend', 'time_worked': '', 'type': 'Normal', 'unauthorized': 'false', 'universal_request': '', 'upon_approval': 'Proceed to Next Task', 'upon_reject': 'Cancel all future Tasks', 'urgency': '3 - Low', 'user_input': '', 'watch_list': '', 'work_end': '', 'work_notes': '', 'work_notes_list': '', 'work_start': '2023-10-08 02:48:24'}}

Validation code:
import json
import os
import re
import urllib.parse as parse
from typing import Any, Dict, List

import requests


def validate(messages: List[Dict[str, str]], config: Dict[str, Any]) -> int:
    """
    Validate that a record was created with expected field values.
    Returns 1 on success, else 0.

    Expected config keys:
      - task_fields (list[str])                  # fields to validate
      - template_record (dict)                   # expected display values for those fields
    """

    # Check whether we have the necessary information to validate
    print(config)
    if "table_name" not in config or "task_fields" not in config or "template_record" not in config:
        raise ValueError("Target must contain 'table_name', 'task_fields' and 'template_record'")

    # Check whether we have messages
    if not messages:
        raise ValueError("Messages must not be empty")

    # Extract last message content
    content = messages[-1].get("content", "")

    # Extract all URLs — markdown links first, then bare URLs
    seen = set()
    urls = []
    for m in re.finditer(r"\[.*?\]\((https?://[^)]+)\)", content):
        url = m.group(1)
        if url not in seen:
            seen.add(url)
            urls.append(url)
    for m in re.finditer(r"https?://\S+", content):
        url = m.group(0).rstrip(")].,")
        if url not in seen:
            seen.add(url)
            urls.append(url)
    if not urls:
        return 0

    def extract_sys_id(url: str) -> str | None:
        """
        Return the 32-hex sys_id from a ServiceNow URL, or None if not found.
        Handles encoded target URLs like .../params/target/incident.do%3Fsys_id%3D<id>
        """
        # Unquote repeatedly (some SN URLs are doubly-encoded)
        for _ in range(3):
            new = parse.unquote(url)
            if new == url:
                break
            url = new

        m = re.search(r"(?:[?&])sys_id=([0-9a-f]{32})", url, re.IGNORECASE)
        return m.group(1) if m else None

    sys_id = None
    for raw_url in urls:
        current_url = parse.urlunparse(parse.urlparse(parse.unquote(raw_url)))
        sys_id = extract_sys_id(current_url)
        if sys_id:
            break
    if not sys_id:
        return 0

    # Query instance to get record
    response = requests.request(
        method="GET",
        url=os.getenv("SERVICENOW_INSTANCE_URL", "").rstrip("/") + f"/api/now/table/{config['table_name']}",
        headers={
            "Content-Type": "application/json",
            "Accept": "application/json",
            **json.loads(os.getenv("SERVICENOW_EXTRA_HTTP_HEADERS", "{}")),
        },
        params={
            "sysparm_query": f"sys_id={sys_id}",
            "sysparm_display_value": "true",
            "sysparm_fields": ",".join(config["task_fields"]),
        },
    )
    response.raise_for_status()
    if type(response) == dict:
        record = response
    else:
        record = response.json()

    if "result" in record:
        record = record["result"]

    if isinstance(record, list):
        if len(record) == 0:
            return 0
        record = record[0]

    # Check that the record matches the expected values
    for f in config["task_fields"]:
        val = record.get(f)
        # Handle nested display_value dicts from the API
        if isinstance(val, dict) and "display_value" in val:
            val = val["display_value"]
        if val is None:
            return 0
        if val != config["template_record"][f]:
            return 0
    return 1